Flutter SDK

flutter

iOS and Android from one pub.dev package. Shake the phone, annotate, send — reports land in the same inbox as your web app's.

Install

terminal
flutter pub add tracebird_flutter
main.dart
import 'package:tracebird_flutter/tracebird_flutter.dart';

void main() async {
  await Tracebird.init(
    projectKey: 'pk_live_a1b2c3',
    environment: Env.name,
    release: '1.4.2',
    trigger: TracebirdTrigger.shake,
    capture: const TracebirdCapture(
      logs: true,
      network: true,
      breadcrumbs: true,
    ),
    privacy: const TracebirdPrivacy(
      maskWidgets: true,
      scrubHeaders: ['authorization'],
    ),
  );

  runApp(
    TracebirdWrapper(          // installs the overlay + root RepaintBoundary
      child: const MyApp(),
    ),
  );
}
⚠ heads upAdd your app's bundle IDs (e.g. com.acme.app, com.acme.beta) to the project's allowlist in Settings — the mobile equivalent of the web origin allowlist.

Options

optiontypedefaultdescription
projectKeyStringRequired — same key as web, or a dedicated mobile project.
triggerTracebirdTriggershakeshake · floatingButton · manual. Shake keeps the UI clean during usability tests.
capture.logsbooltruedebugPrint interceptor, plus adapters for logger and talker.
capture.networkbooltrueDio interceptor provided; http adapter optional. Method, URL, status, duration — never bodies.
capture.breadcrumbsbooltrueNavigatorObserver route trail — how the tester got to this screen.
privacy.maskWidgetsbooltrueWidgets wrapped in TracebirdMask are blanked in every capture.
privacy.scrubHeadersList<String>Headers stripped from captured requests.

Masking sensitive widgets

patient_card.dart
TracebirdMask(
  child: PatientCard(patient: patient),
)

Masked widgets are blanked at capture time, on the device — the real pixels never enter a screenshot.

Triggers

  • Shake (default) — accelerometer with a calibrated threshold and 2 s debounce; on iOS the native UIEventSubtypeMotionShake is used for reliability.
  • Floating button — the classic bubble, for desktop or simulator testing.
  • Manual — trigger from your own UI:
anywhere.dart
Tracebird.report(type: FeedbackType.bug);

Screens with maps, webviews, video

A platform view — a WebView, a Google Map, a camera preview — is not drawn by Flutter, and a naive capture leaves a hole where it sits. Measured on a real WebView on both platforms:

optiontypedefaultdescription
iOSneeds the fallbackRepaintBoundary leaves a hole; UIGraphicsImageRenderer with drawHierarchy captures the view correctly.
Androidno fallback neededPlatform views are composited into the Flutter scene, so RepaintBoundary already contains them.

So the SDK uses Flutter's own capture everywhere and pays for a native capture only on iOS, only on the screens where it detects a platform view. You configure none of it. Content protected by FLAG_SECURE still cannot be captured on Android — the report is sent without a screenshot.

Offline testers

Mobile testers lose network. Reports are persisted locally and replayed on reconnection, with an idempotency key so flaky retries never create duplicates in your inbox.

What a mobile report contains

  • Annotated screenshot (brush, arrow, rect and a blur that destroys the pixels on the device)
  • Logs and failed requests, current route + navigation breadcrumbs
  • Device model, OS version, app version + build number, locale, connectivity
  • Custom metadata via Tracebird.addMetadata()
noteWeb and Flutter reports share one inbox — filter by platform in the dashboard when you need to split them.