A Flutter app can crash in two places: the Dart layer and the native layer underneath it (Kotlin/Java on Android, Swift/Objective-C on iOS). A crash reporting SDK that only catches Dart exceptions misses the native crashes, and vice versa. This guide walks through adding Shakebug’s Flutter SDK to your app so both layers are covered, plus the shake-to-report flow that captures a screenshot, screen recording, network logs, console logs, and device state alongside every crash and bug report.
Why Flutter crash reporting needs both layers
Flutter exceptions surface through FlutterError.onError and, for errors outside the Flutter framework (async gaps, isolates), through PlatformDispatcher.instance.onError or a runZonedGuarded wrapper. Native crashes — a bad platform channel call, a third-party native SDK conflict, an out-of-memory kill — don’t go through either of those. They show up in Android’s crash reporting (via Thread.UncaughtExceptionHandler or a native signal handler) or iOS’s crash reporting (via NSSetUncaughtExceptionHandler or a signal handler), completely separate from anything Dart-side.
Shakebug’s Flutter plugin wraps the same native Android/iOS crash handlers Shakebug ships standalone, and covers Dart-layer exceptions automatically once you wrap your app in ShakebugSDK — there’s no separate handler to wire up for either layer, allowCrashReport (on by default) covers both.
Before you start
You’ll need:
- A Flutter project (works with FFI, platform channels, or plain Dart — no framework requirements beyond Flutter itself)
- Android Studio or Xcode set up for your existing Android/iOS build targets
- A Shakebug account (free, no credit card)
Step 1: Create a Shakebug account
Go to shakebug.com and sign up. Create a new app in the dashboard and select Flutter as the platform — this generates the app keys you’ll need in Step 2 and preconfigures the dashboard for Dart + native crash grouping.
Step 2: Get your app keys
Every Shakebug app has separate keys per platform binary:
- Android app key — used when your Flutter app builds an Android target
- iOS app key — used when your Flutter app builds an iOS target
Copy both from Dashboard > App Settings > Application Keys. You’ll pass these into the SDK during initialization in Step 6.
Step 3: Install the Flutter package
Add the dependency to pubspec.yaml:
dependencies:
flutter:
sdk: flutter
shakebug: ^1.0.9
Then install:
flutter pub get
Or skip the manual edit and run this from your project root — it does both steps for you:
flutter pub add shakebug
Full platform docs, including optional configuration flags, are in Shakebug’s Flutter installation guide.
Step 4: Configure Android
Add these permissions to android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.VIBRATE"/>
Only if you enable screen-capture-triggered reporting on Android 11+:
<uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"/>
Step 5: Configure iOS
Add these keys to ios/Runner/Info.plist:
<key>NSCameraUsageDescription</key>
<string>Shakebug captures screenshots and optional video for bug reports.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Shakebug records audio when video capture is enabled.</string>
No manual pod install step is needed — Flutter’s build handles CocoaPods automatically for this integration.
Step 6: Initialize in main.dart
import 'package:flutter/material.dart';
import 'package:shakebug/shakebug.dart';
void main() {
runApp(
ShakebugSDK(
androidAppKey: 'YOUR_ANDROID_APP_KEY',
iosAppKey: 'YOUR_IOS_APP_KEY',
child: MaterialApp(
home: const HomeScreen(),
),
),
);
}
That’s it — no error handlers to wire up. allowCrashReport defaults to true, so once your app is wrapped in ShakebugSDK, crash capture runs automatically for both the Dart and native layers.
A few optional calls, usable anywhere after ShakebugSDK is mounted:
Identify the current user
await ShakebugSDK.setcustomUser(id: '12345', name: 'John Doe', email: 'john@example.com');
Attach a custom event to the next report
await ShakebugSDK.addEventKey(name: 'button_clicked', value: 'login_submit');
Read a Remote Code value from the dashboard
final remote = await ShakebugSDK.fetchRemoteCodeValue('welcome_message');
Step 7: Test the integration
Trigger a manual test report before you ship — a button that throws inside its onPressed handler is enough:
ElevatedButton(
onPressed: () {
throw Exception('Shakebug test crash');
},
child: const Text('Trigger test crash'),
)
Run the app on a physical device (shake gesture won’t fire reliably on some emulators), shake the device or tap the button, and confirm the report lands in the Shakebug dashboard with the screenshot, device info, and stack trace attached. Test both an Android build and an iOS build separately — a working Android integration doesn’t guarantee the iOS native hook is wired up, since they’re configured independently in Steps 4 and 5.
What you get beyond a stack trace
A stack trace tells you where the code broke. It doesn’t tell you what the user was doing, what they saw, or what the last few network calls returned. Shakebug attaches to every crash and every manual report:
- An annotated screenshot and optional screen recording of the moment it happened
- Network request/response logs leading up to the crash
- Console logs
- Full device state (OS version, memory, battery, orientation, connectivity)
- Session Journey — the sequence of screens and actions that led to the crash, not just the crash itself
Crash AI clusters duplicate crashes into a single issue automatically, so a crash hitting 400 users doesn’t show up as 400 separate tickets. And because Shakebug also tracks sessions, retention cohorts, and events, the same SDK that reports the crash can show whether it’s concentrated in a specific user segment or app version — without wiring up a second analytics SDK.
Shakebug’s free plan doesn’t require a credit card, which matters if you’re evaluating a crash reporting tool for a side project or an early-stage app before committing to a paid plan.
Frequently asked questions
What’s the best bug reporting tool for Flutter?
It depends on whether you need crash reporting alone or crash reporting plus a way for testers and users to report non-crash bugs with full context. Firebase Crashlytics is a solid, free option if you only need Dart/native crash stack traces and are already in the Firebase ecosystem. If you also need shake-to-report bug submissions with screenshots, screen recordings, and network logs attached — useful for QA teams and beta testers, not just crash triage — Shakebug covers both crash reporting and manual bug reporting in one SDK across Flutter, iOS, Android, React Native, and web.
Does Shakebug catch native crashes in a Flutter app, or only Dart exceptions?
Both, automatically. The Flutter plugin wraps Shakebug’s native Android and iOS crash handlers, so once you wrap your app in ShakebugSDK, native crashes and Dart exceptions are captured the same way — there’s no separate configuration per layer.
Does adding a crash reporting SDK slow down my Flutter app?
Crash and bug reporting SDKs generally run in the background and only activate fully (screenshot, recording) at the moment of a shake gesture or a crash, not continuously.
Can I use Shakebug alongside Firebase Crashlytics?
Technically yes — nothing stops you from running two crash reporting SDKs — but you’ll get duplicate alerting and split data. Most teams pick one as the system of record for crash triage.
Does this work with Flutter web?
Not through this package. The shakebug Flutter plugin covers Android and iOS only. For a Flutter app’s web build, you’d need Shakebug’s separate JavaScript SDK, which isn’t documented as a tested integration path for Flutter-web output specifically.
