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

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

Obsly Flutter SDK - Framework-Agnostic #

Obsly Logo

pub package License: MIT

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


Overview #

Obsly offers an advanced observability platform for iOS, Android and Web applications. This Flutter SDK is framework-agnostic and works with any Flutter application architecture while providing Crashlytics-style 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
  • βœ… Advanced Navigation - Ready for go_router, auto_route, and custom navigation systems
  • βœ… Crashlytics-Style Init - Familiar API patterns with enhanced flexibility
  • βœ… Conflict Prevention - Safe coexistence with existing crash reporting systems

Core Capabilities #

  • Automatic UI, navigation, network, console and crash capture
  • 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
    • Error Handling & Conflict Prevention
  • 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 Crashlytics-style 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 Crashlytics, Sentry, etc.
  );

  // πŸ”₯ Crashlytics-style initialization
  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 Crashlytics

void main() async {
  // Initialize Firebase Crashlytics
  await Firebase.initializeApp();
  FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterFatalError;

  // Initialize Obsly with conflict prevention
  ObslySDK.enableAsyncErrorCapture(
    global: true,
    preventConflicts: true, // πŸ›‘οΈ Won't interfere with Crashlytics
  );

  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
    );
  }
}

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', 'OP', 'VIEW', '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 - Crashlytics-style 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(...));
    

Debug tools #

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

Requirements #

  • Flutter >= 3.0.0
  • Dart >= 3.0.0

Getting Help #

Questions or feedback? Email us at info@obsly.tech.

License #

MIT License - see LICENSE file for details.

Support #

Contributing #

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

0
likes
0
points
82
downloads

Publisher

verified publisherobsly.io

Weekly Downloads

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

Repository (GitHub)
View/report issues

Documentation

Documentation

License

unknown (license)

Dependencies

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

More

Packages that depend on obsly_flutter