Migrating from Firebase Crashlytics to Shakebug in React Native
This is for React Native teams who’ve already decided Crashlytics isn’t enough on its own — usually because it has no in-app bug reporting, no session context, and no official React Native SDK at all. If you’re still weighing whether to switch, read the Crashlytics vs. Shakebug comparison first; this post picks up after that decision and covers the mechanics of actually doing it.
Migrating means running both SDKs in parallel for a defined window, not deleting Crashlytics on day one. You want to see Shakebug capturing everything Crashlytics does before you pull the older SDK out. The steps below walk through that in order: install Shakebug next to Crashlytics, run both, compare how each one groups the same crash, move your Jira/Slack/Linear alerting over, then remove Crashlytics once you’re confident.
Step 1: Install Shakebug alongside Crashlytics
Nothing gets removed in this step. Crashlytics keeps running exactly as it is — you’re adding a second SDK next to it.
Install the package:
npm install shakebug-react-native
# or
yarn add shakebug-react-native
iOS setup. Add the three usage-description keys Shakebug needs for shake-to-report (screenshot, screen recording, and photo attachment) to ios/YourProjectName/Info.plist:
<key>NSCameraUsageDescription</key>
<string>Used to attach a screenshot to bug reports</string>
<key>NSMicrophoneUsageDescription</key>
<string>Used to record audio in screen recordings</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Used to save and attach screen recordings</string>
Then install pods:
cd ios && pod install && cd ..
Android setup. Shakebug requires minSdkVersion 24 or later. Check android/build.gradle:
buildscript {
ext {
minSdkVersion = 24 // or later
}
}
Wrap your app. In App.js, wrap your existing tree in ShakebugView. Crashlytics doesn’t need any code change here — it keeps initializing itself the way it already does, through @react-native-firebase/app and your existing GoogleService-Info.plist / google-services.json:
import React from 'react';
import ShakebugView from 'shakebug-react-native';
// your existing Crashlytics import stays exactly as it is
import crashlytics from '@react-native-firebase/crashlytics';
export default function App() {
return (
<ShakebugView
Android_appkey="YOUR_ANDROID_APP_KEY"
iOS_appkey="YOUR_IOS_APP_KEY"
>
{/* your existing app tree, Crashlytics untouched */}
<YourExistingApp />
</ShakebugView>
);
}
Crash capture in Shakebug is on by default (allowCrashReport defaults to true) — mounting ShakebugView is the whole setup, no separate crash-reporting init call. Get your app keys from the Shakebug dashboard under your project’s SDK instructions page after creating a free project — no credit card needed to get this far.
If you use NavigationContainer in the same file, pass independent so it doesn’t fight ShakebugView for the navigation ref:
<ShakebugView Android_appkey="YOUR_ANDROID_APP_KEY" iOS_appkey="YOUR_IOS_APP_KEY">
<NavigationContainer independent>
{/* your app */}
</NavigationContainer>
</ShakebugView>
Step 2: Run both in parallel for a defined window
Ship a build with both SDKs live and leave it that way for a couple of full release cycles — long enough to cover at least one app version rollout end to end. [ESTIMATE — unverified] Two to four weeks is a reasonable starting window for most teams; adjust to your own release cadence rather than treating it as a fixed number.
What to watch during the window:
- Parity: is every crash that lands in Crashlytics also showing up in Shakebug? Spot-check a handful of Crashlytics issues against the Shakebug dashboard each week rather than waiting until the end of the window to find a gap.
- New catches: does Shakebug surface anything Crashlytics missed? Different SDKs hook the exception handler at different points in app startup, so this can go either way.
- Alert fatigue: with two tools both notifying on the same crash, your team gets the same incident twice. Mute one side’s notification channel (not its data capture) for the parallel-run window rather than turning off crash alerting entirely — see Step 4 for where those channels live.
[VERIFY — needs device test] Both Crashlytics and Shakebug install a global uncaught-exception handler on iOS and Android (NSSetUncaughtExceptionHandler / Thread.setDefaultUncaughtExceptionHandler underneath the JS layer). Most modern crash SDKs chain onto whatever handler is already installed rather than replacing it outright, but confirm on an actual device build — for both platforms — that installing Shakebug after Crashlytics doesn’t cause one SDK to silently swallow the other’s reports, before you treat this parallel-run data as reliable.
Step 3: Compare how each tool groups the same crash
This is usually where a team decides how much they trust the new tool’s grouping before they commit. [VERIFY] The example below is an illustrative composite built from a common React Native failure mode, not a real customer’s crash data — swap it for an actual example pulled from your own two dashboards before this goes live.
Say your app throws TypeError: Cannot read property 'name' of undefined from a profile screen component, on iOS 17.4, 17.5, and 18.0. Because your JS bundle is minified and rebuilt on every release (and possibly patched again via CodePush/OTA between releases), the exact line-and-column offset of that same source line shifts across builds — bundle 1 reports it at 1:284219, bundle 2 at 1:284331, bundle 3 at 1:284198.
Crashlytics groups issues primarily by matching stack trace frames. [VERIFY — confirm current grouping behavior against firebase.google.com/docs/crashlytics/manage-issues before stating this as a firm claim] When the blamed frame’s offset changes between builds, that can be enough for Crashlytics to open what looks like a new issue rather than folding it into the existing one — so the same null-check bug shows up as three separate issues with three separate “first seen” dates and three small occurrence counts, none of which look urgent on their own.
Shakebug’s Crash AI clusters against the de-obfuscated stack (once you’ve uploaded your bundle’s source map to the dashboard) rather than the raw minified offset, so it recognizes the same root cause across all three builds and keeps it as one issue — first-seen date from the earliest build, one running occurrence count, and the full list of affected app versions and devices in one place instead of three thin ones.
The practical upshot: don’t judge a duplicate-crash count on either side by the raw issue list. Pick one bug you know recurs across builds and trace it through both dashboards before you decide which one’s grouping you trust more.
Step 4: Migrate your Jira, Slack, and Linear alerts
Once you trust what Shakebug is capturing, move your team’s alerting over so triage happens in one place instead of two.
Jira. In the Shakebug dashboard, go to Integrations, click Add Integration, and select Jira. Authenticate with your Jira account, pick the project and issue type new bugs and crashes should create, and confirm the connection. From here, any bug or crash Shakebug captures can push to Jira with the screenshot, logs, and device details already attached — either on demand or automatically for every new report, depending on how you configure it.
Slack. Same panel — add the Slack integration, authorize the Shakebug Slack app for your workspace, and pick the channel that should receive new bug and crash notifications. If your team was using Firebase’s own Slack integration for Crashlytics velocity alerts (Firebase Console → Project Settings → Integrations → Slack), disable that once Shakebug’s Slack notifications are confirmed working, so the same crash doesn’t page the channel twice.
Linear. Add the Linear integration from the same Integrations panel, connect your Linear workspace, and choose the team and project that new issues should land in. If your Jira/Linear routing from Crashlytics was ever custom-built — a Zapier zap or a Cloud Function reading Crashlytics’ BigQuery export, since Crashlytics has no native Jira or Linear integration of its own — retire that pipeline once Shakebug’s native integration is confirmed working, rather than leaving both running.
Give the new integrations a few real bug reports before you fully retire the old alert paths, the same way you validated crash capture in Step 2.
Step 5: What Crashlytics still does better
A migration guide that only lists gaps in the tool you’re leaving isn’t a fair one. A few things Crashlytics has that Shakebug doesn’t try to match:
- Gemini-powered AI crash insights built directly into the Firebase console, explaining likely causes and suggested fixes on top of the raw stack trace.
- Native Android Studio and Google Play Console (Vitals) integration — crash data surfaces inside tools your Android team is already in, without a separate dashboard tab.
- Deeper Firebase ecosystem tie-in — if you’re already using Firebase Analytics, Performance Monitoring, or Remote Config, Crashlytics data sits alongside it in the same console.
- Completely free, no usage ceiling. Crashlytics doesn’t meter by MAU or event volume the way most paid crash/bug tools eventually do.
[VERIFY] Shakebug is also the younger product of the two by a meaningful margin, which mostly shows up as a smaller integration catalog and less enterprise compliance depth than either Crashlytics or the larger observability platforms — worth weighing if compliance certifications are a hard requirement for your team, not just a nice-to-have.
None of that is a reason to stay Crashlytics-only if the gap you’re solving is in-app bug reporting, session context, or having one SDK across React Native and web — it’s context for what you’re trading off, not a reason to skip the migration.
Step 6: Remove the Crashlytics SDK
Once Shakebug has run alongside Crashlytics through at least one full release cycle and you’ve confirmed parity (Step 2) and moved your alerting (Step 4), pull Crashlytics out.
Uninstall the package:
npm uninstall @react-native-firebase/crashlytics
# also remove @react-native-firebase/app if you're not using any
# other Firebase product (Analytics, Remote Config, etc.) in this app
npm uninstall @react-native-firebase/app
iOS cleanup (Podfile). Remove any explicit Crashlytics pod entry if you added one manually, then reinstall pods so the removed native module is dropped from the build:
# ios/Podfile — remove if present:
# pod 'Firebase/Crashlytics'
cd ios && pod install && cd ..
If Crashlytics’ dSYM-upload build phase script (typically named something like “Upload Crashlytics dSYM” or referencing ${PODS_ROOT}/FirebaseCrashlytics/run) was added to your Xcode build phases, remove that phase too — [VERIFY — needs device test] an archive build with a leftover build-phase script pointing at a removed pod will fail, so check this in Xcode directly rather than assuming pod install cleans it up on its own. Remove GoogleService-Info.plist only if nothing else in the app still depends on it.
Android cleanup (Gradle). In android/build.gradle, remove the Crashlytics Gradle plugin classpath if it’s not needed for anything else:
// android/build.gradle — remove if present:
// classpath 'com.google.firebase:firebase-crashlytics-gradle:VERSION'
In android/app/build.gradle, remove the plugin application and dependency:
// android/app/build.gradle — remove:
// apply plugin: 'com.google.firebase.crashlytics'
// implementation 'com.google.firebase:firebase-crashlytics'
Remove google-services.json only if no other Firebase product in the app still needs it.
Code diff. Strip the Crashlytics import and any manual logging calls — Shakebug’s automatic capture replaces this, nothing needs to take its place:
import ShakebugView from 'shakebug-react-native';
- import crashlytics from '@react-native-firebase/crashlytics';
export default function App() {
- crashlytics().setCrashlyticsCollectionEnabled(true);
-
return (
<ShakebugView Android_appkey="YOUR_ANDROID_APP_KEY" iOS_appkey="YOUR_IOS_APP_KEY">
<YourExistingApp />
</ShakebugView>
);
}
Also remove any scattered crashlytics().log(...) or crashlytics().recordError(...) calls elsewhere in the codebase — a project-wide search for crashlytics() after the package uninstall will catch anything left over, since those calls will otherwise throw at runtime once the module is gone.
[VERIFY — needs device test] Build and run on a real iOS and Android device (not just the simulator/emulator) after this cleanup, and trigger a test crash, before shipping the release that removes Crashlytics — confirm Shakebug still captures it and that the build doesn’t fail on a leftover native reference.
Frequently asked questions
Do I need to remove Crashlytics before I can add Shakebug? No. They install as two independent SDKs — Shakebug doesn’t touch your existing Crashlytics setup, so you can add it, run both, and remove Crashlytics later once you’re confident, in that order.
Will running both SDKs at once double my crash alerts? Yes, until you mute one side’s notification channel. Both will capture and report the same crash independently during the parallel-run window — that’s expected, not a bug — so mute Crashlytics’ or Shakebug’s alert channel (not its data capture) for that period rather than turning off crash reporting on either side.
How long should I run Crashlytics and Shakebug in parallel? Long enough to cover at least one full release cycle — most teams land somewhere around two to four weeks, though that depends on your own release cadence rather than being a fixed rule.
Does Shakebug support Jira, Slack, and Linear the same way Crashlytics does? Shakebug has native integrations for all three, connected from the dashboard’s Integrations tab. Crashlytics itself only has a native Slack integration for velocity alerts; Jira and Linear routing from Crashlytics is typically custom-built via Zapier or its BigQuery export, so migrating those usually means retiring a custom pipeline rather than switching a built-in one.
Is Shakebug free to try during the migration? Yes. Shakebug’s Basic plan is free with no credit card — 3 projects, 3 members, 500 monthly active users, and 10-day retention — which covers a parallel-run window on most single-app projects before you’d need to size up.
Get started
Install shakebug-react-native next to your existing Crashlytics setup and run both for one release cycle before you decide anything. If you haven’t made the call to switch yet, the full Crashlytics vs. Shakebug comparison covers that. Sign up free to get your app keys.
