obsly_flutter 1.0.1 copy "obsly_flutter: ^1.0.1" to clipboard
obsly_flutter: ^1.0.1 copied to clipboard

Advanced Flutter SDK for comprehensive user behavior analytics, UI event tracking, automatic screenshot capture with debug tools, and GoRouter navigation support.

Obsly Flutter SDK - Advanced User Behavior Analytics #

Obsly Logo

pub package License: MIT

πŸš€ Now supports MaterialApp, CupertinoApp, GoRouter, and custom Flutter architectures!


Overview #

Obsly delivers comprehensive user behavior analytics and observability for iOS, Android and Web applications. This Flutter SDK works seamlessly with any Flutter application architecture and provides intuitive initialization patterns.

πŸ”₯ New Framework-Agnostic Features #

  • βœ… MaterialApp Support - Full backward compatibility, zero breaking changes
  • βœ… CupertinoApp Support - Native iOS styling preserved, no forced MaterialApp wrapper
  • βœ… Custom Architecture Support - Works with any Flutter widget hierarchy
  • βœ… GoRouter Integration - Full support for GoRouter with automatic detection and UI event handling
  • βœ… Advanced Navigation - Ready for go_router, auto_route, and custom navigation systems
  • βœ… Dio HTTP Client Support - Simple dio.addObsly() integration for Dio HTTP monitoring
  • βœ… Intuitive Integration - Clean API patterns with enhanced flexibility
  • βœ… Conflict Prevention - Safe coexistence with existing crash reporting systems

Core Capabilities #

  • Automatic UI, navigation, network, console and crash capture
  • HTTP client monitoring (native http package and dio package)
  • Optional screenshot capture on UI and rage-click events
  • Performance transactions and steps
  • Custom metrics (counter, gauge, histogram timer)
  • Tags, context, session and user identification

For API parity details, see the browser SDK documentation in the repository browser/README.md.

Table of Contents #

  • Installation
  • Framework-Agnostic Initialization
  • App Wrapping (Any Architecture)
  • Framework Examples
    • MaterialApp Integration
    • CupertinoApp Integration
    • Custom Architecture Integration
  • Advanced Features
    • Navigation Integration
    • Dio HTTP Client Integration
    • Error Handling & Conflict Prevention
  • Routing and Navigation Support
    • GoRouter Integration
    • Traditional Navigator Support
    • Navigation Events Captured
    • Custom Navigation Solutions
    • Troubleshooting Navigation Issues
  • Configuration
  • Developer Methods
    • Manage Sessions
    • Client Identification
    • Application Identification
    • Tag
    • Screenshot
    • Performance
    • Metrics
    • Application Context
    • SDK Control
    • Miscellaneous
  • Debug tools
  • Migration Guide
  • Requirements
  • Getting Help
  • License

Installation #

Add the dependency:

dependencies:
  obsly_flutter: ^0.2.0

Framework-Agnostic Initialization #

The new API provides intuitive initialization patterns that work with any Flutter architecture:

import 'package:flutter/material.dart';
import 'package:obsly_flutter/obsly_sdk.dart';

void main() async {
  // πŸ”₯ Optional: Configure async error capture (conflict-safe)
  ObslySDK.enableAsyncErrorCapture(
    global: true,
    preventConflicts: true, // Safe with existing error reporting systems
  );

  // πŸ”₯ Initialize with error capture
  ObslySDK.runWithAsyncErrorCapture(() async {
    WidgetsFlutterBinding.ensureInitialized();

    await ObslySDK.instance.init(
      const InitParameters(
        obslyKey: 'YOUR_OBSLY_KEY',
        instanceURL: 'https://api.obsly.io',
        debugMode: true,
        logLevel: LogLevel.debug,
        config: ObslyConfig(
          enableDebugTools: true,
          enableScreenshotOnUi: true,
          rageClick: RageClickConfig(
            active: true,
            screenshot: true,
            screenshotPercent: 0.25,
          ),
        ),
      ),
    );

    runApp(MyApp()); // Works with ANY Flutter app!
  });
}

App Wrapping (Any Architecture) #

Framework-Agnostic Wrapping #

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Your app - MaterialApp, CupertinoApp, or Custom
    final yourApp = MaterialApp(
      title: 'My App',
      home: HomePage(),
    );

    // 🎯 Framework-agnostic wrapping - auto-detects app type
    return ObslySDK.instance.wrapApp(
      app: yourApp,
      enableDebugTools: true,
    );
  }
}

Framework Examples #

MaterialApp Integration (Backward Compatible) #

class MaterialBankingApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final materialApp = MaterialApp(
      title: 'Banking App',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
      ),
      initialRoute: '/',
      routes: {
        '/': (context) => LoginScreen(),
        '/dashboard': (context) => DashboardScreen(),
        '/transactions': (context) => TransactionsScreen(),
      },
    );

    // βœ… All MaterialApp properties preserved exactly
    return ObslySDK.instance.wrapApp(
      app: materialApp,
      enableDebugTools: true,
    );
  }
}

CupertinoApp Integration (iOS Native) #

class iOSBankingApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final cupertinoApp = CupertinoApp(
      title: 'iOS Banking',
      theme: CupertinoThemeData(
        primaryColor: CupertinoColors.systemBlue,
      ),
      home: CupertinoPageScaffold(
        navigationBar: CupertinoNavigationBar(
          middle: Text('Banking'),
        ),
        child: iOSHomeScreen(),
      ),
    );

    // βœ… Native iOS styling preserved, no MaterialApp forced
    return ObslySDK.instance.wrapApp(
      app: cupertinoApp,
      enableDebugTools: true,
    );
  }
}

Custom Architecture Integration #

class CustomArchitectureApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final customApp = Container(
      decoration: BoxDecoration(
        gradient: LinearGradient(
          colors: [Colors.purple, Colors.blue],
        ),
      ),
      child: CustomNavigationSystem(
        child: MyCustomScreens(),
      ),
    );

    // βœ… No forced MaterialApp wrapper
    return ObslySDK.instance.wrapApp(
      app: customApp,
      customNavigationProvider: CustomNavigationProvider(),
      enableDebugTools: true,
    );
  }
}

Advanced Features #

go_router Support

final GoRouter _router = GoRouter(
  routes: [
    GoRoute(path: '/', builder: (context, state) => HomeScreen()),
    GoRoute(path: '/profile', builder: (context, state) => ProfileScreen()),
  ],
);

class GoRouterApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final app = MaterialApp.router(routerConfig: _router);

    return ObslySDK.instance.wrapApp(
      app: app,
      customNavigationProvider: GoRouterProvider(), // πŸ”„ Coming soon
    );
  }
}

auto_route Support

@AutoRouterConfig()
class AppRouter extends _$AppRouter {
  @override
  List<AutoRoute> get routes => [
    AutoRoute(page: HomeRoute.page, path: '/'),
    AutoRoute(page: ProfileRoute.page, path: '/profile'),
  ];
}

class AutoRouteApp extends StatelessWidget {
  final _appRouter = AppRouter();

  @override
  Widget build(BuildContext context) {
    final app = MaterialApp.router(routerConfig: _appRouter.config());

    return ObslySDK.instance.wrapApp(
      app: app,
      customNavigationProvider: AutoRouteProvider(), // πŸ”„ Coming soon
    );
  }
}

Error Handling & Conflict Prevention #

Coexistence with Other Error Reporting

void main() async {
  // Initialize your existing error reporting system
  await initializeExistingErrorReporting();

  // Initialize Obsly with conflict prevention
  ObslySDK.enableAsyncErrorCapture(
    global: true,
    preventConflicts: true, // πŸ›‘οΈ Safe coexistence
  );

  ObslySDK.runWithAsyncErrorCapture(() async {
    await ObslySDK.instance.init(params);
    runApp(MyApp());
  });
}

Custom Error Handling

void main() async {
  // Configure with custom error handler
  ObslySDK.enableAsyncErrorCapture(
    global: true,
    captureIsolateErrors: false,
    preventConflicts: true,
  );

  // Listen to async errors
  ObslySDK.onAsyncError.listen((error) {
    print('Custom handling: ${error.error}');
    // Your custom logic here
  });

  ObslySDK.runWithAsyncErrorCapture(() async {
    await ObslySDK.instance.init(params);
    runApp(MyApp());
  });
}

Advanced Setup (Manual Control) #

For cases requiring granular initialization control:

import 'package:flutter/widgets.dart';
import 'package:obsly_flutter/obsly_sdk.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  ObslySDK.run(() async {
    try {
      await ObslySDK.instance.init(
        InitParameters(
          obslyKey: 'YOUR_OBSLY_KEY',
          instanceURL: 'https://api.obsly.com',
          appName: 'MyFlutterApp',
          appVersion: '1.0.0',
          logLevel: LogLevel.error,
          debugMode: false,
          config: const ObslyConfig(
            enableAutomaticCapture: true,
            enableScreenshotOnUi: false,
            enableRageClickScreenshot: false,
          ),
          // sessionID: 'optional-custom-session-id',
        ),
      );

      runApp(const MyApp());
    } catch (e) {
      // App continues without Obsly if initialization fails
      runApp(const MyApp());
    }
  });
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ObslySDK.instance.wrapAppLegacy(
      app: MaterialApp(
        title: 'My App',
        home: const HomePage(),
      ),
      enableDebugTools: false, // set true to show the debug overlay
    );
  }
}

Dio HTTP Client Integration #

For applications using the popular Dio HTTP client, Obsly provides seamless integration with a simple extension API:

Basic Usage

import 'package:dio/dio.dart';
import 'package:obsly_flutter/obsly_sdk.dart';

class ApiClient {
  final Dio dio;

  ApiClient() : dio = Dio() {
    dio.addObsly(); // ✨ One-liner integration
  }

  Future<Map<String, dynamic>> getUser(String id) async {
    final response = await dio.get('/users/$id');
    return response.data;
  }
}

Advanced Configuration

class ApiService {
  final Dio _publicApi;
  final Dio _privateApi;

  ApiService() :
    _publicApi = Dio(BaseOptions(baseUrl: 'https://api.example.com')),
    _privateApi = Dio(BaseOptions(baseUrl: 'https://internal.example.com')) {

    // Monitor public API calls
    _publicApi.addObsly();

    // Private API without monitoring (skip addObsly())
    _privateApi.interceptors.add(AuthInterceptor());
  }
}

Features

  • βœ… Automatic Request/Response Capture: Monitors all Dio HTTP requests and responses
  • βœ… Error Tracking: Captures DioExceptions and HTTP errors
  • βœ… Timing Metrics: Records request duration and performance data
  • βœ… Duplicate Prevention: Intelligent detection prevents adding multiple Obsly interceptors
  • βœ… Zero Configuration: Works out of the box with existing Dio instances
  • βœ… Coexistence: Works alongside your existing Dio interceptors

Verification

final dio = Dio();
dio.addObsly();

// Check if monitoring is active (optional)
print('Obsly monitoring: ${dio.hasObslyMonitoring}'); // true

// Make requests - automatically monitored
await dio.get('https://api.example.com/data');

All HTTP requests made through Dio will now appear in your Obsly dashboard alongside native http package requests.

Configuration #

Init parameters (parity with JS Browser SDK):

Parameter Type Required Default Description
ObslyKey String Yes β€” Authorization API key
instanceURL String Yes β€” API server URL
remoteConfigURL String? No β€” Remote config URL
proEnv bool? No β€” Production environment flag
appVersion String? No β€” App version
appName String? No β€” App name
logLevel String? No "error" Allowed values: null, error, warn, log, debug
config ObslyConfig? No see below Advanced configuration
debugMode bool? No false Enable debug overlay and verbose behavior
sessionID String? No β€” Custom session ID on init

ObslyConfig structure:

Parameter Type Default Description
enableAutomaticCapture bool true Enable all automatic interceptors (UI, navigation, HTTP, console, crashes)
enableDebugTools bool false Render floating debug tools when wrapping app
logLevel LogLevel LogLevel.error Runtime log level (use setLogLevel for string-based)
userId String? β€” Pre-set user id
appName String? β€” Override app name
appVersion String? β€” Override app version
enableScreenshotOnUi bool false Screenshot on UI and lifecycle events
enableRageClickScreenshot bool false Screenshot subset for rage-click detection
requestBlacklist List<String>? β€” Wildcard URL blacklist for HTTP capture
requestBodyWhitelist List<RequestBodyConfig>? β€” URLs to capture request/response body on errors
requestHeadersWhitelist List<RequestHeadersConfig>? β€” URLs to capture whitelisted headers on errors
rageClick RageClickConfig? β€” Rage click configuration
rateLimits RateLimits? β€” Event type rate limits
enableCrashes bool? β€” Toggle crash events
enableLifeCycleLog bool? β€” Toggle lifecycle events
enableRequestLog bool? β€” Toggle request events
enableTagger bool? β€” Toggle tag events
enablePerformance bool? β€” Toggle performance events
enableUI bool? β€” Toggle UI events

Rate Limit Configuration #

You can control the rate of captured events. Configure per-event-type limits inside ObslyConfig.rateLimits.

Event types:

  • base, request, tag, console, ui, metric, error, performance, navigation

Parameters:

Parameter Type Default Description
interval int 1000 Interval in milliseconds for rate limiting
trailing bool false Send trailing events after the rate limit period
bucketSize int 10 Max events to process within an interval (request: 20)
emptyBucketDelay int 1000 Delay in milliseconds before emptying the bucket
rejectWhenBucketFull bool false If true, reject when full (console, error: true)

Example:

final params = InitParameters(
  ObslyKey: 'KEY',
  instanceURL: 'https://api.url',
  config: ObslyConfig(
    rateLimits: const RateLimits(
      error: RateLimitConfig(
        interval: 2000,
        bucketSize: 15,
        trailing: true,
        emptyBucketDelay: 2000,
        rejectWhenBucketFull: false,
      ),
      ui: RateLimitConfig(
        bucketSize: 20,
        emptyBucketDelay: 2000,
      ),
    ),
  ),
);

Request Headers Config #

Control which headers are captured for requests within a status range and URL pattern.

Parameter Type Example Description
url String https://api.example.com/sensitive/* URL to capture headers (supports wildcards)
fromStatus int 400 Min HTTP status (inclusive)
toStatus int 599 Max HTTP status (inclusive)
headers List<String> ["content-type","x-request-id"] Specific headers to capture (supports wildcards)

Example:

InitParameters(
  ObslyKey: 'KEY',
  instanceURL: 'https://api.url',
  config: const ObslyConfig(
    requestHeadersWhitelist: [
      RequestHeadersConfig(
        url: 'https://api.example.com/sensitive/*',
        fromStatus: 400,
        toStatus: 599,
        headers: ['content-type', 'x-request-id'],
      ),
    ],
  ),
);

Request Body Config #

Capture request and/or response bodies on error ranges for matching URLs.

Parameter Type Example Description
url String https://api.example.com/* URL to capture body (supports wildcards)
fromStatus int 400 Min HTTP status (inclusive)
toStatus int 599 Max HTTP status (inclusive)
captureRequestBody bool true Capture request body
captureResponseBody bool true Capture response body

Example:

const config = ObslyConfig(
  requestBodyWhitelist: [
    RequestBodyConfig(
      url: 'https://api.example.com/*',
      fromStatus: 400,
      toStatus: 599,
      captureRequestBody: true,
      captureResponseBody: true,
    ),
  ],
);

Wildcards #

Use wildcards in URL patterns and header names:

  • URL: https://example.com/*, https://*.example.com/*, *.example.com/*
  • Header: *content*, content*, *type, x-*

Developer Methods #

All functions are available on ObslySDK.instance. For readability, performance and metrics are also exposed via namespaced getters Performance and Metrics.

Manage Sessions:

await ObslySDK.instance.closeCurrentSession();
await ObslySDK.instance.createNewSession('custom-session-id');

Client Identification:

await ObslySDK.instance.setUserID('user-123');
await ObslySDK.instance.setPersonID('person-456');
await ObslySDK.instance.setPassportID('passport-789');
await ObslySDK.instance.setContractID('contract-000');

Application Identification:

await ObslySDK.instance.setAppName('MyNewApp');
await ObslySDK.instance.setAppVersion('1.2.0');

Tag:

await ObslySDK.instance.addTag(
  [Tag(key: 'user_tier', value: 'premium')],
  'User Properties',
);

Screenshot:

await ObslySDK.instance.addScreenshot();
final base64Image = await ObslySDK.instance.getScreenshot();

Performance:

await ObslySDK.instance.Performance.startTransaction('DASHBOARD', 'Load Dashboard');
await ObslySDK.instance.Performance.startStep('Load Dashboard', 'DASHBOARD');
await ObslySDK.instance.Performance.finishStep('Load Dashboard', 'DASHBOARD');
await ObslySDK.instance.Performance.endTransaction('DASHBOARD');

Metrics:

ObslySDK.instance.Metrics.incCounter('CLICK_EVENT', 'FBL', 'OP', 'VIEW', 'OK');
ObslySDK.instance.Metrics.setGauge('CPU', 0.75, fbl: 'FBL', operation: 'OP', view: 'VIEW', state: 'OK');
ObslySDK.instance.Metrics.startHistogramTimer('FETCH', 'FBL', 'OP', 'VIEW');
ObslySDK.instance.Metrics.endHistogramTimer('FETCH', 'FBL', 'OP', 'VIEW', 'OK');

Application Context:

await ObslySDK.instance.setView('HOME');
await ObslySDK.instance.setOperation('ONBOARDING');
await ObslySDK.instance.setFunctionalBlock('AUTH');

SDK Control:

await ObslySDK.instance.pauseTracker();
await ObslySDK.instance.resumeTracker();
await ObslySDK.instance.setRequestsBlacklist(['https://*.sensitive.com/*']);
await ObslySDK.instance.setLogLevel('warn'); // 'null' | 'error' | 'warn' | 'log' | 'debug'

final session = ObslySDK.instance.getSessionInfo();

Miscellaneous:

await ObslySDK.instance.addFeedback('5', 'Great experience');

Migration Guide #

Migrating to Framework-Agnostic SDK #

From v0.x.x to v1.0.0 (Zero Breaking Changes)

Your existing MaterialApp code works unchanged:

Before (Old SDK - Still Works):

void main() {
  ObslySDK.run(() {
    runApp(
      ObslySDK.wrapApp(
        app: MaterialApp(...),
        obslyKey: 'your-key',
        instanceURL: 'https://api.obsly.io',
      ),
    );
  });
}

After (New SDK - Recommended):

void main() async {
  ObslySDK.runWithAsyncErrorCapture(() async {
    WidgetsFlutterBinding.ensureInitialized();

    await ObslySDK.instance.init(
      const InitParameters(
        obslyKey: 'your-key',
        instanceURL: 'https://api.obsly.io',
      ),
    );

    runApp(MyApp());
  });
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ObslySDK.instance.wrapApp(
      app: MaterialApp(...), // Works exactly the same
    );
  }
}

Benefits of Migration

  • βœ… CupertinoApp Support - Add iOS native support
  • βœ… Custom Architecture - Use any Flutter widget hierarchy
  • βœ… Better Error Handling - Advanced async error capture
  • βœ… Conflict Prevention - Safe with existing crash reporting
  • βœ… Navigation Flexibility - Ready for go_router, auto_route

Migration Checklist

  1. Update Initialization (Optional but recommended):

    // Replace ObslySDK.run() with:
    ObslySDK.runWithAsyncErrorCapture(() async {
      await ObslySDK.instance.init(params);
      runApp(MyApp());
    });
    
  2. Update App Wrapping (Optional but recommended):

    // Replace ObslySDK.wrapApp() with parameters with:
    return ObslySDK.instance.wrapApp(app: yourApp);
    
  3. Enable Conflict Prevention (If using other crash tools):

    ObslySDK.enableAsyncErrorCapture(preventConflicts: true);
    
  4. Test Different Architectures (Optional):

    // Try CupertinoApp
    return ObslySDK.instance.wrapApp(app: CupertinoApp(...));
    
    // Or custom architecture
    return ObslySDK.instance.wrapApp(app: CustomWidget(...));
    

Routing and Navigation Support #

Obsly Flutter SDK provides comprehensive support for both traditional Navigator and modern routing solutions like GoRouter.

πŸš€ GoRouter Integration #

The SDK automatically detects and integrates with GoRouter-based applications. When using MaterialApp.router or CupertinoApp.router, the SDK:

  • βœ… Auto-detects GoRouter configuration and initializes navigation tracking
  • βœ… Captures navigation events with route names and transitions
  • βœ… Handles UI events correctly even with GoRouter's navigation architecture
  • βœ… Maintains zero configuration - works out of the box

Example: GoRouter Setup

import 'package:go_router/go_router.dart';
import 'package:obsly_flutter/obsly_sdk.dart';

final GoRouter router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => const HomePage(),
    ),
    GoRoute(
      path: '/profile',
      builder: (context, state) => const ProfilePage(),
    ),
  ],
);

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ObslySDK.instance.wrapApp(
      app: MaterialApp.router(
        routerConfig: router,
        title: 'My GoRouter App',
      ),
      enableDebugTools: true, // Optional debug overlay
    );
  }
}

Manual GoRouter Initialization (Optional)

For advanced use cases, you can manually initialize GoRouter tracking:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await ObslySDK.instance.init(/* your config */);

  // Optional: Manual GoRouter initialization
  await ObslySDK.initializeGoRouter(router);

  runApp(MyApp());
}

Traditional Navigator Support #

The SDK continues to provide full support for traditional Navigator-based applications:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ObslySDK.instance.wrapApp(
      app: MaterialApp(
        title: 'My Navigator App',
        initialRoute: '/',
        routes: {
          '/': (context) => const HomePage(),
          '/profile': (context) => const ProfilePage(),
        },
      ),
    );
  }
}

The SDK automatically captures the following navigation events:

  • Route Changes: Push, pop, replace operations
  • Route Names: Full path information and route identification
  • Navigation Timing: Transition durations and timestamps
  • Navigation Context: Previous and current route information

Custom Navigation Solutions #

For custom navigation implementations, you can integrate with Obsly's navigation tracking:

// Custom navigation provider
class CustomNavigationProvider extends NavigationProvider {
  // Implement your custom navigation tracking
}

// Register your provider
ObslySDK.instance.wrapApp(
  app: yourCustomApp,
  customNavigationProvider: CustomNavigationProvider(),
);

Troubleshooting Navigation Issues #

If navigation events are not appearing:

  1. Verify GoRouter Version: Ensure you're using GoRouter 6.0.0 or later
  2. Check Debug Logs: Enable debug mode to see navigation initialization logs
  3. Manual Initialization: Try manual GoRouter initialization if auto-detection fails
// Enable debug mode for navigation troubleshooting
await ObslySDK.instance.init(
  InitParameters(
    debugMode: true, // Shows detailed navigation logs
    logLevel: LogLevel.debug,
    // ... other config
  ),
);

Debug Tools #

Enable the overlay by passing enableDebugTools: true to wrapApp. The overlay lets you inspect captured events and screenshots during development.

⚠️ Important: Production Usage #

Never enable debug tools in production builds. Debug tools show internal SDK messages and operations that should not be visible to end users.

Development:

ObslySDK.instance.wrapApp(
  app: yourApp,
  enableDebugTools: true, // βœ… OK for development
);

Production:

ObslySDK.instance.wrapApp(
  app: yourApp,
  enableDebugTools: false, // ❌ Always false in production
);

Debug Tools Features #

When enabled, debug tools provide:

  • Real-time event monitoring
  • Session lifecycle notifications (including "new session created" messages)
  • Screenshot capture and viewing
  • Network request inspection
  • Performance metrics
  • Configuration management
  • Rule execution monitoring

Important: Event Sending Behavior

When debug tools are enabled (enableDebugTools: true), automatic event sending is disabled by default. Events are captured and stored locally but are not sent to the Obsly server automatically. This allows developers to inspect events before sending them.

To send events to the server when debug tools are enabled:

  • Use the "Send" button (πŸ“€) in the Events tab of the debug overlay
  • Call ObslySDK.instance.forceFlush() programmatically
  • The manual send will transmit all pending events to the server

This behavior ensures developers have full control over when events are sent during development and testing.

All debug notifications and overlays are intended for developers only and should never be seen by end users.

Requirements #

  • Flutter >= 3.0.0
  • Dart >= 3.0.0

Getting Help #

Questions or feedback? Email us at help@obsly.io.

License #

MIT License - see LICENSE file for details.

Support #

Contributing #

Contributions are welcome! Please read our Contributing Guide for details.

0
likes
130
points
79
downloads

Publisher

verified publisherobsly.io

Weekly Downloads

Advanced Flutter SDK for comprehensive user behavior analytics, UI event tracking, automatic screenshot capture with debug tools, and GoRouter navigation support.

Repository (GitHub)
View/report issues

Documentation

Documentation
API reference

License

MIT (license)

Dependencies

battery_plus, connectivity_plus, device_info_plus, dio, flutter, flutter_svg, hive, hive_flutter, http, jmespath, meta, package_info_plus, path_provider, shared_preferences, uuid

More

Packages that depend on obsly_flutter