cxorbi_flutter 0.1.0 copy "cxorbi_flutter: ^0.1.0" to clipboard
cxorbi_flutter: ^0.1.0 copied to clipboard

Cxorbi analytics for Flutter: session replay, heatmaps, screens, gestures, funnels, performance and error capture for iOS and Android.

Cxorbi Flutter SDK #

Session replay, heatmaps, journeys, performance and error analytics for Flutter apps — iOS and Android from a single integration.

The SDK captures wireframe replays (no screenshots ever leave the device), gestures with target elements, screen views, app performance and errors. Image and custom-render assets are placeholders by default and can be uploaded only through explicit opt-in privacy settings. Records use the industry-standard two-dimension identity model:

  • platform — the host OS the session ran on: ios or android
  • framework — always flutter

So a Flutter session shows up under iOS or Android in the dashboard with a Flutter badge, exactly like React Native sessions do.

📚 Full documentation lives in the Docs section of your Cxorbi dashboard and at cxorbi.com — getting started, screen tracking, identity, events, transactions, session replay, heatmaps, customer journeys, funnels, error analysis, privacy & masking, API reference, data collection, performance impact, compatibility, troubleshooting.

Requirements #

  • Flutter 3.27+ / Dart 3.5+
  • iOS and Android (web/desktop are not captured)
  • Works with flutter build --obfuscate — all widget detection uses compile-time type checks, never runtimeType strings

Installation #

flutter pub add cxorbi_flutter

No manual native (Pod/Gradle) setup is required for the default integration — standard Flutter dependency resolution wires the iOS/Android plugin.

Quick start #

import 'package:cxorbi_flutter/csq.dart';
import 'package:flutter/material.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await CSQ().start(
    startConfig: StartConfig.withApiKey(
      id: 'YOUR_API_KEY', // Dashboard -> Integrations
      options: const AnalyticsOptions(
        enableInteractionsAutocapture: true,
      ),
    ),
  );

  // The SDK is opted OUT by default — nothing is captured or sent until
  // optIn() is called. Call it right away, or after your consent dialog.
  await CSQ().optIn();

  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorObservers: [CxorbiNavigatorObserver()], // automatic screen tracking
      // ...
    );
  }
}

Verify your integration #

  1. Run the app — the console prints Cxorbi Flutter SDK 0.1.0 starting — platform: ios, framework: flutter, then Cxorbi Flutter SDK consent accepted — session: ….
  2. Navigate to the first named screen. Replay/error capture starts at the first screenview, matching CSQ behavior.
  3. Tap around.
  4. Open Session Replay in the dashboard — the session appears within a minute under the iOS/Android tab with a Flutter badge. Screens appear in Heatmaps → iOS/Android once a screen has interactions.

Screen tracking #

CxorbiNavigatorObserver tracks every named route pushed, popped or replaced. Unnamed routes are ignored rather than guessed — give your routes names (RouteSettings(name: '/checkout')) or use the callbacks below.

MaterialApp(
  navigatorObservers: [
    CxorbiNavigatorObserver(
      // Skip dialogs / splash screens:
      excludeRoute: (route) => route.settings.name == '/splash',
      // Rename or derive names dynamically (return null = use route name):
      screenNameProvider: (route) =>
          route.settings.name == '/p' ? '/product-detail' : null,
      // Attach route-level variables:
      customVarsProvider: (route) => const [
        CustomVar(index: 1, name: 'area', value: 'checkout'),
      ],
    ),
  ],
)

Manual #

Call Cxorbi.instance.screen(name) whenever a screen becomes visible. Manual calls always win over the observer. You need manual calls for:

  • PageView — call in onPageChanged
  • TabBar — call from a TabController listener
  • Modals / bottom sheets you want treated as screens
Cxorbi.instance.screen('/checkout');
// CSQ-style alias:
await CSQ().trackScreenview(screenName: '/checkout');

Naming guidance (matches Contentsquare best practice): keep names short and template-based, separate words with /, - or _, and encode state in the name when it changes the layout — e.g. /cart-empty vs /cart.

Privacy & masking #

Replays are wireframes: layout boxes, text, colors — never pixels or screenshots. On top of that:

  • Input fields are masked by default. Only explicitly unmask fields after confirming your privacy policy allows it.
  • All other text is masked by default (MaskingMode.text), with the mode controlled from the dashboard (Settings → Recording Privacy). An explicit maskingMode in CxorbiConfig overrides the dashboard.
  • Images and custom render output are placeholders by default. Enable captureImageAssets / captureRenderBoundaryAssets only for reviewed, non-sensitive surfaces.
  • Modes: none (capture text), digits (mask digits only), text / full (mask all text, length-preserving *).

To mask a specific widget regardless of the global mode, wrap it in CxorbiMask:

CxorbiMask(
  child: Text(user.cardNumber),
)

Everything inside a CxorbiMask subtree is masked by default, even when the global mode is none. For scoped overrides:

CxorbiMask(
  config: const CxorbiMaskingConfig(maskTexts: false),
  child: const Text('Public label'),
)

Identify users #

Cxorbi.instance.identify('user-123', {
  'plan': 'premium',
  'country': 'IN',
});

await CSQ().addUserProperties(properties: {'campaign': 'summer'});

Custom events #

Cxorbi.instance.track('feature_used', {'feature': 'dark_mode'});
await CSQ().addEventProperties(properties: {'app_version': '2.1.4'});
await CSQ().trackEvent(eventName: 'feature_used', properties: {'feature': 'dark_mode'});

Events feed journeys and funnels alongside automatic screen views.

Transactions #

Cxorbi.instance.trackTransaction(
  orderId: 'ord_001',
  revenue: 4999,        // minor units
  currency: 'USD',
  items: [
    {'sku': 'SKU-1', 'qty': 1},
  ],
);

Errors #

Uncaught Flutter framework errors and 4xx/5xx Dart HttpClient API errors are captured automatically after the first screenview. Query strings are stripped from API error URLs. Mask path segments with CS-style patterns:

CSQ().setURLMaskingPatterns(patterns: [
  'https://api.example.com/users/:user_id/address/:address',
]);

Report handled errors yourself:

try {
  await api.submit();
} catch (e, st) {
  Cxorbi.instance.reportError(e, st);
}

For native plugin, WebView or custom-client API failures that do not flow through Dart HttpClient, report the failed request explicitly:

CSQ().reportNetworkError(
  method: 'POST',
  url: Uri.parse('https://api.example.com/orders/123'),
  statusCode: 500,
);
await Cxorbi.instance.optIn();  // start capture (required once per launch)
Cxorbi.instance.optOut();       // stop all capture immediately

Sessions #

  • A session id is created at init(). Mobile replay/error/perf capture starts only after both optIn() and the first screenview.
  • Sessions rotate after 5 minutes in background.
  • Cxorbi.instance.sessionId returns the current id.
  • To join a session minted by your backend analytics, pass CxorbiConfig(sessionId: ...).

Configuration reference #

CxorbiConfig field Default Purpose
apiKey — (required) Organization API key from the dashboard
apiUrl https://api.cxorbi.com/api API base URL
dashboardUrl null Enables metadata.sessionReplayUrl
sessionId auto (fl_…) Externally minted session id
userId null Initial user id (else call identify)
maskingMode dashboard setting Explicit masking override
maskingConfig inherit Fine-grained text/input/image/interaction masking
captureFrames true Wireframe replay frames
captureGestures true Taps / swipes / scrolls
captureErrors true Automatic error capture
capturePerformance true App/screen/network performance samples
captureNetworkErrors true Automatic 4xx/5xx API errors through HttpOverrides
captureNativeNetworkErrors true Native/WebView bridge for API error reports
captureImageAssets false Opt-in unmasked image asset upload for replay
captureRenderBoundaryAssets false Opt-in CxorbiCaptureBoundary custom-render upload
sessionReplayAutoStart true Start replay automatically after first screenview
urlMaskingPatterns [] API error URL path masking patterns
offlineQueueEnabled true Encrypted bounded disk queue on iOS/Android
offlineQueueMaxEntries 200 Max pending requests before oldest-drop
offlineQueueMaxBytes 5 MB Max pending bytes before oldest-drop
maxReplayAssetBytes 512 KB Max single visual replay asset
debug false Verbose logging

How capture works (and what it costs) #

A frame walker runs at most every 300 ms, only after Flutter actually painted a new frame, and only re-emits when screen content changed (an idle screen sends a keyframe every 10 s). Trees are capped at 800 nodes / depth 60. Gestures are observed on the global pointer router — no GestureDetector wrapping, no interference with your app's gesture handling.

Troubleshooting #

  • No startup logCxorbi.init() not reached; ensure it runs in main() before runApp().
  • Session never appearsoptIn() was not called, or the device can't reach apiUrl (check for HTTP errors with debug: true).
  • Screens all named unknown — routes are unnamed and no manual screen() calls; add CxorbiNavigatorObserver and route names.
  • Text shows as **** — that's the default privacy mode; change it in Dashboard → Settings → Recording Privacy or via maskingMode.
32
likes
0
points
1.13k
downloads

Publisher

unverified uploader

Weekly Downloads

Cxorbi analytics for Flutter: session replay, heatmaps, screens, gestures, funnels, performance and error capture for iOS and Android.

Homepage

Topics

#analytics #session-replay #heatmaps #monitoring

License

unknown (license)

Dependencies

crypto, cryptography, ffi, flutter, flutter_secure_storage, http, path_provider

More

Packages that depend on cxorbi_flutter

Packages that implement cxorbi_flutter