Setting Up Crash Reporting in React Native with Sentry
AI generated
RN
native
React Native · Sentry · Crash Reporting · Monitoring
Setting Up Crash Reporting in React Native with Sentry
from SDK installation to symbolicated stack traces

A crash that never shows up in a dashboard never gets fixed. Sentry crash reporting captures JavaScript errors and native iOS and Android crashes in React Native apps alike, symbolicates the stack traces, and makes visible what users actually experience, before a bad app store review becomes the first signal.

18 min read @sentry/react-native · sentry-cli · source maps React Native 0.74+ · Expo · iOS · Android

1. What crash reporting in React Native really solves

A React Native app lives in two runtimes at once: the JavaScript engine (Hermes or JSC) and the native iOS or Android layers. An error can originate in either, but without Sentry crash reporting a development team sees none of it. The user sees a red screen, closes the app, or uninstalls it. The error message, device type, operating system version, and exact code path stay unknown unless someone manually reports the incident to support.

This is exactly where crash reporting with Sentry comes in: an installed SDK automatically captures unhandled JavaScript exceptions, promise rejections, and native signal crashes, enriches them with context, and sends them to a central dashboard. The team learns within minutes, not weeks, that a new release is crashing on specific Android devices, and can pinpoint the exact line in the source code instead of guessing at symptoms.

The difference between an app with and without Sentry crash reporting shows up most clearly right after a release: without monitoring, problems surface through declining store ratings and support tickets, often days later. With Sentry, a spike in error rate appears in the dashboard within minutes, tied to the exact release version, affected device model, and a stack trace that leads straight to the faulty line of code.

2. SDK setup: installing @sentry/react-native

Installing @sentry/react-native starts with the Sentry wizard, which automatically adjusts the native configuration for iOS and Android, registers the Metro bundler hook for source maps, and writes the base configuration into the app's entry file. The wizard replaces manual edits to AppDelegate.mm and MainApplication.kt that were still needed in older Sentry versions.

Central to the setup is calling Sentry.init() as early as possible in the app lifecycle, before the root component renders. The DSN (data source name) identifies the Sentry project, tracesSampleRate controls the performance sampling rate, and enableNative activates the connection to the native crash handlers of sentry-cocoa and sentry-android. Without this native coupling, Sentry crash reporting would only see JavaScript errors and completely miss crashes originating in native modules.


// App.tsx — initialize Sentry as early as possible in the app lifecycle
import * as Sentry from '@sentry/react-native';

Sentry.init({
  dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0',
  environment: __DEV__ ? 'development' : 'production',
  tracesSampleRate: 0.2,
  enableNative: true,
  enableAutoSessionTracking: true,
  release: 'my-app@2.4.0+42',
  beforeSend(event) {
    // Strip personally identifiable data before it leaves the device
    if (event.user) {
      delete event.user.email;
    }
    return event;
  },
});

export default Sentry.wrap(function App() {
  return <RootNavigator />;
});

3. Source maps and readable JS stack traces

A JavaScript bundle in a production build is minified. Without source maps, Sentry crash reporting only delivers cryptic line numbers in a compressed file, with no mapping back to the actual source code. The Sentry Metro plugin automatically generates source maps during bundling and uploads them via sentry-cli, tied to the exact release version and build.

The critical part is that the release identifier used on the client must exactly match the one used during source map upload. If it diverges, Sentry finds no matching mapping and keeps displaying minified code. A CI step that keeps release creation, source map upload, and deployment reliably in sync prevents this common failure mode entirely.


#!/usr/bin/env bash
# Upload source maps for a production release before app store submission
set -euo pipefail

RELEASE="my-app@2.4.0+42"

sentry-cli releases new "$RELEASE"
sentry-cli releases files "$RELEASE" upload-sourcemaps \
  ./dist \
  --dist 42 \
  --rewrite

sentry-cli releases finalize "$RELEASE"
echo "Source maps uploaded and release finalized: $RELEASE"

4. Native crashes: dSYM and ProGuard mapping

Native crashes often originate in third-party libraries, in native modules with memory errors, or in bridging code between JavaScript and the native layer. For Sentry crash reporting to deliver readable stack traces here instead of just memory addresses, the dSYM file for every build must be uploaded on the iOS side. It contains the debug symbols that map an address in compiled binary code back to a function and line.

On the Android side, the ProGuard or R8 mapping file plays the same role for obfuscated code. Without this mapping, a crash report shows only renamed classes and method names such as a.b.c, which makes debugging practically impossible. The Sentry Gradle plugin automatically uploads the mapping file on every release build, provided it is correctly wired into build.gradle.


// ios/AppDelegate.mm — Sentry native SDK integration point for symbolicated crashes
// Xcode Build Phase "Upload Debug Symbols to Sentry" runs sentry-cli after archiving:
//   sentry-cli debug-files upload --include-sources ./MyApp.xcarchive.dSYM.zip
//
// Ensure Build Settings > Debug Information Format is "DWARF with dSYM File"
// for both Debug and Release configurations, otherwise no dSYM is produced.

A stack trace alone rarely answers how a user ended up in the failing state. Breadcrumbs log the last actions before a crash: navigation events, API calls, button taps, and console output. Sentry crash reporting collects many of these breadcrumbs automatically, for example through the React Navigation integration, which logs every screen change.

On top of that, custom breadcrumbs and tags can be set, such as the pseudonymized user ID, the active feature flag set, or the cart state in a shopping app. This enrichment turns an isolated stack trace into a traceable story: which user, which state, which action immediately preceded the crash.


// Enrich crash reports with custom breadcrumbs and user context
import * as Sentry from '@sentry/react-native';

function addToCart(product: Product) {
  Sentry.addBreadcrumb({
    category: 'cart',
    message: `Added product ${product.id} to cart`,
    level: 'info',
  });
  cartStore.add(product);
}

Sentry.setUser({ id: hashUserId(currentUser.id) });
Sentry.setTag('feature_flag.checkout_v2', 'enabled');

6. Release health and sessions

Beyond individual crashes, Sentry crash reporting also delivers aggregated metrics: the crash-free session rate shows what percentage of app sessions ended without a crash, broken down by release version. A drop in this rate after a rollout is a reliable early warning signal, often before support tickets arrive.

Sessions are tracked automatically once enableAutoSessionTracking is enabled. For staged rollouts, for example through staged rollouts in the Play Store, the crash-free rate can be compared per rollout stage, enabling a data-driven decision on whether to halt or continue the rollout instead of relying on gut feeling.

7. Performance tracing beyond crash reporting

Sentry crash reporting and performance monitoring share the same infrastructure. With tracesSampleRate enabled, tracing measures app start times, navigation transitions, and network request durations without an additional SDK. A slow screen transition is often only revealed through these traces, whereas it would go unnoticed in classic crash reporting alone.

Especially valuable is linking traces to error events: a timeout on an API call that shortly afterward leads to a crash appears in the same dashboard as a connected sequence of events. This dramatically shortens root-cause analysis, because performance data and error data no longer need to be merged across separate tools.

8. Integrating sentry-cli into CI/CD pipelines

Manual source map and dSYM uploads are error-prone because they get forgotten easily. The robust solution wires sentry-cli directly into the release pipeline: after every successful build, a new Sentry release is created automatically, source maps and debug symbols are uploaded, and the release is marked as deployed.

This automation ensures that Sentry crash reporting delivers full symbolication from the first minute after rollout, instead of leaving a gap between app store approval and a manual upload. An additional CI step can even verify that a matching source map actually exists for every uploaded bundle, failing the build if it does not.


{
  "sentryCliConfig": {
    "org": "my-organization",
    "project": "my-app-react-native",
    "urlPrefix": "~/",
    "rewrite": true,
    "ignore": ["node_modules", "android", "ios"]
  }
}

// android/app/build.gradle — Sentry Gradle plugin uploads ProGuard/R8 mapping automatically
// apply plugin: "io.sentry.android.gradle"
//
// sentry {
//     autoUploadProguardMapping = true
//     includeProguardMapping = true
// }
//
// This runs during `./gradlew assembleRelease` and requires SENTRY_AUTH_TOKEN
// to be present as an environment variable in the CI job.

9. Sentry compared to Bugsnag and Crashlytics

Sentry is not the only option for crash reporting in React Native, but the combination of an open ecosystem, combined error and performance monitoring, and a mature React Native integration makes it an obvious choice for teams that want more than pure crash reporting.

Criterion Sentry Bugsnag Firebase Crashlytics
Integrated performance tracing Yes, same platform Separate add-on product Separate Firebase Performance SDK
Self-hosting possible Yes, open source No, SaaS only No, Google Cloud only
Source map handling Automated via Metro plugin Manual via CLI No native JS source map concept
Pricing model Based on event volume Based on user count Free on the basic tier
Breadcrumb enrichment Very flexible, many integrations Solid, fewer integrations Limited, Logcat-focused

Firebase Crashlytics scores with a free entry point and deep Google Play integration, but falls behind Sentry crash reporting on source map handling and flexible context enrichment. Bugsnag is functionally close to Sentry, but requires a separate product for performance data. For teams that want crashes, performance, and releases in one tool, Sentry usually remains the more pragmatic choice.

Mironsoft

React Native monitoring, crash reporting and release automation

Catch crashes before your users report them?

We set up Sentry crash reporting in your React Native app end to end, including source maps, native symbolication, and CI integration, so every crash is traceable immediately.

Sentry setup

SDK integration, source maps and native symbolication for iOS and Android

CI/CD integration

Automated releases, sentry-cli uploads, and mapping verification

Monitoring consulting

Release health, alerting rules, and dashboard setup for your team

10. Summary

Sentry crash reporting turns invisible crashes into traceable, prioritizable error reports. Installing the SDK with Sentry.init() captures JavaScript errors, and the native coupling via sentry-cocoa and sentry-android extends coverage to native crashes. Source maps and dSYM uploads ensure stack traces stay readable instead of showing minified code or raw memory addresses.

Breadcrumbs and context tags turn an isolated error into a traceable user story, release health delivers aggregated metrics for rollout decisions, and integrating sentry-cli into the CI/CD pipeline ensures symbolication works from the first second after rollout. Combining these building blocks consistently cuts the time between crash and fix from days down to minutes.

React Native Crash Reporting with Sentry — Key Takeaways

SDK setup

Sentry.init() as early as possible, enableNative: true couples JS and native crash handlers.

Symbolication

Source maps for JS, dSYM for iOS, ProGuard/R8 mapping for Android, without these three stack traces stay unreadable.

Context

Breadcrumbs, tags, and release health turn a stack trace into a traceable story.

Automation

sentry-cli in the CI/CD pipeline prevents forgotten uploads and symbolication gaps.

11. FAQ: React Native Crash Reporting with Sentry

1What is Sentry crash reporting?
The combination of the @sentry/react-native SDK and dashboard that captures JS and native errors, symbolicates them, and enriches them with context.
2Isn't JS error handling enough?
No, native crashes in libraries or bridging code are only captured with native Sentry coupling.
3How long does setup take?
Basic install usually under an hour, full CI integration a half day to a full day.
4Why unreadable stack traces?
Missing source map, dSYM, or ProGuard upload, or a mismatched release identifier between client and upload.
5What are breadcrumbs?
A chronological log of the last user actions before a crash, useful for reconstructing the failure path.
6What is release health?
The crash-free session rate per release, an early warning signal after every rollout.
7Does Sentry replace a performance tool?
Often yes, since performance tracing and crash reporting share the same platform.
8How do I protect personal data?
Remove fields via beforeSend and enable data scrubbing in the Sentry project settings.
9Must sentry-cli run manually?
No, always automate it in the CI/CD pipeline to avoid symbolication gaps.
10Does it work with Expo?
Yes, via the Sentry Expo plugin and EAS Build the upload is handled automatically during the build process.