Sentry Integration with React Native Expo: A Practical Quick Guide
Step-by-step guide to integrating Sentry error monitoring into a React Native Expo app. Covers SDK initialization, Expo Router instrumentation, session replay, source map uploads for EAS Build and EAS Update, and common pitfalls to avoid.
This guide walks through integrating Sentry into a React Native Expo application, from installation to production-grade source map uploads. It covers the critical configuration details, Expo Go limitations, session replay setup, and the gotchas that tend to waste hours if you encounter them unprepared.
Prerequisites
Before starting, you need:
- An Expo project using SDK 50 or later (SDK 52+ recommended)
- A Sentry account (free tier provides 5,000 errors/month)
- A Sentry React Native project created in the dashboard
- Three identifiers from Sentry: Organization slug, Project name, and DSN
- An Organization Auth Token generated from Sentry settings
Step 1: Installation
The Sentry wizard automates most of the setup. Run it from your project root:
The wizard handles Metro config, Expo plugin config, and basic SDK initialization. If you prefer manual setup or the wizard does not work in your environment, install the package directly:
Manual setup requires configuring three files yourself, which the following steps cover in detail.
Step 2: Metro Configuration
Sentry needs to hook into the Metro bundler for source map generation. Replace your metro.config.js with:
If you already have a custom Metro config, wrap your existing config with getSentryExpoConfig instead of replacing it entirely.
Step 3: Expo Plugin Configuration
Add the Sentry plugin to your app.json (or app.config.js):
Warning: Never put
authTokeninapp.jsonorapp.config.js. This config gets embedded in the app bundle and is accessible at runtime. Set the auth token as an environment variable or EAS secret instead. This was a documented security issue in the Expo SDK 50 migration docs.
Step 4: SDK Initialization with Expo Router
The main initialization goes in your root layout file. This example includes performance monitoring with Expo Router navigation tracking, environment configuration, and session replay:
A few things worth noting in this configuration:
tracesSampleRate: 0.2in production captures 20% of transactions. Setting this to1.0in production will burn through your quota quickly and can impact app performance.replaysOnErrorSampleRate: 1.0captures session replays for every error, which is the most valuable use case. General session replays at0.1provide a sample without excessive data.isRunningInExpoGo()guards prevent enabling native-only features in Expo Go, where they would silently fail or crash.
Step 5: Understanding Expo Go vs Development Builds
This is one of the most common sources of confusion. Expo Go does not include Sentry's native modules, which limits functionality significantly.
The isRunningInExpoGo() guard prevents enabling native-only features when running in Expo Go:
For full Sentry functionality, always validate with a development build or EAS Build before shipping.
Step 6: Error Boundaries
Sentry provides an ErrorBoundary component that catches React rendering errors and reports them automatically:
The beforeCapture callback lets you add context tags, making it easier to filter and group errors in the Sentry dashboard.
Note: In React development mode, React rethrows errors caught by error boundaries to the global error handler, which can cause duplicate reports. Test error boundary behavior in production builds.
Step 7: Source Maps -- EAS Build and EAS Update
Getting readable stack traces in production requires properly uploaded source maps. The process differs between EAS Build and EAS Update.
EAS Build (Automatic)
For native builds, source map upload is automatic. Just set the auth token as an EAS secret:
That is it. The Sentry Expo plugin handles the rest during the build process.
EAS Update (Manual)
OTA updates do not automatically upload source maps. After every eas update, you need to upload them manually:
Automate this in your CI/CD pipeline to avoid shipping updates with unreadable stack traces.
Step 8: Tagging EAS Update Metadata
When using OTA updates, tagging Sentry events with update metadata makes it possible to filter errors by update version:
This is particularly useful when an OTA update introduces a regression -- you can immediately identify which update group caused the spike in errors.
Step 9: Verifying the Integration
Before going to production, verify that errors appear correctly in your Sentry dashboard with a simple test component:
Check the Sentry dashboard after triggering each error. Verify that stack traces are properly symbolicated -- you should see your original source file names and line numbers, not minified code.
Tip: The native crash test only works in development builds, not in Expo Go. If pressing the button does nothing, you are likely running in Expo Go.
Troubleshooting
Source Maps Show Minified Code
Cause: Source maps were not uploaded or the release/dist values do not match between the app and the uploaded maps.
Fix: Use automatic release naming (the default). If you set custom release or dist values in Sentry.init(), the automatic upload script cannot detect them. Either stick with defaults or manually upload source maps with matching release/dist values.
Navigation Tracking Not Working
Cause: registerNavigationContainer was never called with the navigation ref.
Fix: Make sure useNavigationContainerRef() is called in the same component where Sentry is initialized, and register the ref in a useEffect.
Duplicate Error Reports in Development
Cause: React's development mode rethrows errors caught by error boundaries to the global handler.
Fix: Test error boundary behavior in production builds. You can also disable Sentry in development with enabled: !__DEV__ if the noise is distracting.
sentry-expo Package Errors
Cause: The sentry-expo package was deprecated with the release of Expo SDK 50 and is no longer maintained.
Fix: Migrate to @sentry/react-native directly. Sentry provides a migration guide in their documentation.
High Event Volume Burning Through Quota
Cause: Sample rates set too high for production.
Fix: Use conservative rates: tracesSampleRate: 0.1-0.2, replaysSessionSampleRate: 0.1. Keep replaysOnErrorSampleRate: 1.0 since error replays are the most valuable.
Version Compatibility
Note: Version 8 updates native SDKs (Cocoa v9, CLI v3, Android Gradle Plugin v6) with breaking changes in minimum version requirements. Check the release notes before upgrading.
Key Takeaways
- Use the wizard --
npx @sentry/wizard@latest -i reactNativehandles most setup automatically. - Development builds are essential -- Expo Go only captures JavaScript errors. Native crashes, frame tracking, and session replay require a development build.
- Secure your auth token -- Never put
SENTRY_AUTH_TOKENinapp.json. Use EAS secrets or environment variables. - EAS Update needs manual source map upload -- Unlike EAS Build, OTA updates do not automatically upload source maps. Automate
sentry-expo-upload-sourcemapsin your CI pipeline. - Use conservative sample rates in production -- 10-20% for traces, 10% for session replays, 100% for error replays.
- Tag OTA updates -- Use
expo-updatesmetadata on Sentry scope so you can filter errors by update version.
References
- Sentry Expo Manual Setup - Official Sentry documentation for Expo integration
- Expo Sentry Guide - Expo's guide to using Sentry in Expo projects
- Sentry Expo Router Instrumentation - Navigation performance tracking with Expo Router
- Sentry Error Boundary - ErrorBoundary component documentation
- Sentry Source Map Upload for Expo - Source map configuration for EAS Build and EAS Update
- Sentry Session Replay for React Native - Mobile session replay setup and configuration
- Sentry Release Configuration - Release and dist naming conventions
- Migrate from sentry-expo - Migration guide from deprecated sentry-expo package
- sentry-react-native GitHub Releases - Release notes and changelog for the SDK
- Expo SDK 50 Security Notice - Security notice about auth token exposure in plugin configuration