bugban_flutter

Crash reporting and performance monitoring for Flutter, from Bugban.

flutter pub add bugban_flutter
import 'package:bugban_flutter/bugban_flutter.dart';

void main() {
  BugbanFlutter.run(
    options: BugbanOptions(
      apiKey: 'bb_your_project_key',
      host: 'https://bugban.online',
      environment: 'production',
      release: '1.0.0',
    ),
    appRunner: () => runApp(const MyApp()),
  );
}

Why run and not just init

Flutter has four separate error paths, and an integration that wires up only the obvious one silently misses whole classes of crash:

Path Catches
FlutterError.onError errors inside build, layout and paint
PlatformDispatcher.instance.onError uncaught async errors (Flutter 3.3+)
runZonedGuarded everything else on the zone
Isolate.current.addErrorListener crashes on a background isolate

BugbanFlutter.run installs all four. runZonedGuarded only catches errors raised inside its callback, so initialising outside the zone and calling runApp inside it loses async errors without a word — which is why run owns both steps.

If your app already has its own zone, use BugbanFlutter.init(...) instead and keep the zone handler yourself:

await BugbanFlutter.init(options);
runZonedGuarded(() => runApp(const MyApp()), (e, s) {
  Bugban.capture(e, stackTrace: s, handled: false);
});

Every handler is chained, never replaced. In debug the existing one draws the red screen and in release your app may have its own reporter on it; taking either away silently is not something a monitoring SDK gets to do.

Screen names

MaterialApp(
  navigatorObservers: [BugbanNavigatorObserver()],
  routes: {'/': (_) => const HomePage(), '/checkout': (_) => const CheckoutPage()},
)

Without it a report names a widget class; with it, it says it broke on /checkout. The same observer times screen transitions (SCREEN_LOAD).

Screenshots

Off by default, and that default is deliberate: a screenshot is pixels, so once it is taken nothing downstream can tell a password field from any other grey rectangle. Masking has to happen before the capture.

// 1. opt in
BugbanOptions(/* ... */, captureScreenshots: true)

// 2. mark what to capture
RepaintBoundary(key: BugbanScreenshot.rootKey, child: MaterialApp(/* ... */))

// 3. cover what must not be seen
BugbanMask(child: TextField(obscureText: true))

No extra package needed — Flutter's own RepaintBoundary rasterises the tree.

Performance

Core Web Vitals do not translate to a phone; these do:

  • APP_START — how long until the app is usable. Call BugbanFlutter.markAppReady() when your first screen has its data; if you never do, the first frame is used instead.
  • SCREEN_LOAD — time to move to another screen (from the navigator observer).
  • JANK — the longest stuttering frame.

Offline queue

On by default, backed by shared_preferences. A phone loses signal in a lift and a crash can end the process before a single request completes, so events are written to disk before the request goes out and cleared only once the server has taken them.

Not covered yet

Native crashes (ANR, SIGSEGV) never reach the Dart layer and are not captured. Dart errors, async errors, isolate crashes and caught exceptions all are.

Licence

MIT

Libraries

bugban_flutter
Bugban for Flutter.