Integrating Sentry into a React Native app built with Expo and setting it up in a CI/CD pipeline requires some specific configurations due to Expo’s managed workflow and build process.
Key Differences for Expo
- Managed Workflow:
- Expo’s managed workflow abstracts native code (iOS/Android), so you don’t directly modify
ios/orandroid/directories. - Sentry’s native crash reporting requires additional setup for Expo, as native modules are handled differently.
- Expo uses its own build service (EAS Build) or Turtle CLI for generating native binaries.
- Expo’s managed workflow abstracts native code (iOS/Android), so you don’t directly modify
- Source Maps and Artifacts:
- Expo generates JavaScript bundles and source maps differently, requiring specific commands to export and upload them to Sentry.
- For native crash symbolication, you need to upload artifacts like dSYMs (iOS) or Proguard mappings (Android) from Expo’s build outputs.
- CI/CD Pipeline:
- Expo apps typically use EAS Build for CI/CD, which integrates with Sentry for automated source map and artifact uploads.
- Configuration focuses on Expo CLI, EAS CLI, and Sentry CLI in the pipeline, rather than direct Xcode or Gradle modifications.
- Native Crash Reporting:
- Expo’s managed workflow limits direct access to native code, but Sentry’s React Native SDK supports Expo via the
@sentry/react-nativepackage with EAS Build or custom dev clients.
- Expo’s managed workflow limits direct access to native code, but Sentry’s React Native SDK supports Expo via the
Best Practices for Sentry with Expo
1. Install and Configure Sentry
The initial setup is similar to the React Native guide, but with Expo-specific considerations.
-
Install Sentry SDK: Install the Sentry React Native SDK:
npm install @sentry/react-native- No native linking is required for Expo’s managed workflow, as Expo handles native dependencies.
-
Run Sentry Wizard: Use the Sentry Wizard to streamline setup:
npx @sentry/wizard -i reactNative- The wizard will:
- Create a
sentry.propertiesfile. - Prompt for your Sentry DSN and project.
- Add example code to your app.
- Create a
- For Expo, the wizard may not modify
ios/orandroid/(since they’re managed), but it sets up JavaScript-level integration.
- The wizard will:
-
Initialize Sentry: Create a
sentry.tsfile for initialization, as shown in the previous guide:
import * as Sentry from '@sentry/react-native';
import { Integrations } from '@sentry/tracing';
export function initSentry() {
Sentry.init({
dsn: process.env.SENTRY_DSN || 'YOUR_SENTRY_DSN', // Use env variable
integrations: [
new Integrations.ReactNativeTracing({
routingInstrumentation: new Sentry.ReactNavigationInstrumentation(),
}),
],
environment: process.env.NODE_ENV || 'development',
release: `my-app@${process.env.EXPO_APP_VERSION || '1.0.0'}`, // Dynamic version from Expo
tracesSampleRate: 1.0, // Adjust for production
enableNative: true, // Required for native crash reporting
enableNativeCrashHandling: true,
debug: process.env.NODE_ENV === 'development',
});
}
- Expo-Specific Notes:
- Use
process.env.EXPO_APP_VERSIONto dynamically set thereleasefield, matching yourapp.jsonorpackage.jsonversion. - Ensure
enableNative: truefor native crash reporting, which works with EAS Build or custom dev clients.
- Use
- Integrate in App:
Initialize Sentry in your
App.tsxand set up an error boundary, as shown previously:
import React, { useEffect } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import * as Sentry from '@sentry/react-native';
import { initSentry } from './sentry';
import RootNavigator from './navigation/RootNavigator';
initSentry();
export default function App() {
const navigationRef = React.useRef(null);
useEffect(() => {
Sentry.getCurrentHub()
.getIntegration(Sentry.ReactNavigationInstrumentation)
.registerNavigationContainer(navigationRef);
}, []);
return (
<Sentry.ErrorBoundary
fallback={({ error, componentStack }) => (
<View style=>
<Text>Something went wrong!</Text>
<Text>{error.message}</Text>
<Text>{componentStack}</Text>
</View>
)}
>
<NavigationContainer ref={navigationRef}>
<RootNavigator />
</NavigationContainer>
</Sentry.ErrorBoundary>
);
}
- Use Environment Variables:
Store your DSN securely using
react-native-dotenvor Expo’s configuration:-
Install
react-native-dotenv:npm install react-native-dotenv -
Add to
babel.config.js:module.exports = { presets: ['module:metro-react-native-babel-preset'], plugins: [ ['module:react-native-dotenv', { moduleName: '@env', path: '.env', }], ], }; -
Create a
.envfile:SENTRY_DSN=https://your-dsn@sentry.io/123 EXPO_APP_VERSION=1.0.0 -
Import in
sentry.ts:import { SENTRY_DSN } from '@env'; Sentry.init({ dsn: SENTRY_DSN, ... });
-
- Best Practices:
- Use
app.jsonorapp.config.jsto define your app version and ensure it matches thereleasein Sentry. - Test initialization in development using Expo Go (JavaScript errors only) and in a production build for native crashes.
- Use
2. Enable Native Crash Reporting
Expo’s managed workflow requires EAS Build or a custom dev client for native crash reporting, as Expo Go does not support native modules.
- Use EAS Build:
-
Set up Expo Application Services (EAS) for building your app:
npm install -g eas-cli eas login eas build:configure -
Create an
eas.jsonfile to define build profiles:{ "build": { "production": { "releaseChannel": "production", "distribution": "store", "env": { "SENTRY_DSN": "https://your-dsn@sentry.io/123", "EXPO_APP_VERSION": "1.0.0" } }, "preview": { "releaseChannel": "preview", "distribution": "internal" } } } -
Run a build:
eas build --platform all --profile production
-
- Enable Native Crashes:
- Ensure
enableNative: truein your Sentry configuration. - With EAS Build, Sentry’s native crash reporting is automatically enabled, as the
@sentry/react-nativeSDK includes native dependencies.
- Ensure
- Custom Dev Client (Optional):
-
If you need native modules in development, create a custom dev client:
expo prebuild expo run:ios expo run:android -
This generates
ios/andandroid/directories, allowing native crash testing in development.
-
- Best Practices:
- Test native crashes in a production build, as Expo Go does not support native crash reporting.
- Use EAS Build for consistent production builds with Sentry integration.
- Verify native crash reporting by triggering a test crash (see below).
3. Source Maps and Symbolication
Expo handles JavaScript bundles and native artifacts differently, requiring specific steps for source maps and symbolication.
- Generate and Upload JavaScript Source Maps:
-
Export your app bundle with source maps:
expo export --dev --sourcemaps- This generates a
dist/folder with bundles and source maps (e.g.,ios/index.bundleandios/index.bundle.map).
- This generates a
-
Upload source maps to Sentry using Sentry CLI:
npm install -g @sentry/cli export SENTRY_AUTH_TOKEN=YOUR_AUTH_TOKEN sentry-cli sourcemaps upload \ --org YOUR_ORG \ --project YOUR_PROJECT \ --release my-app@1.0.0 \ ./dist
-
- Upload Native Artifacts:
- iOS (dSYMs):
-
After an EAS Build, download the build artifacts:
eas build --platform ios --profile production - Extract dSYMs from the
.ipaor build artifacts (usually in a.dSYMfolder). -
Upload to Sentry:
sentry-cli upload-dif \ --org YOUR_ORG \ --project YOUR_PROJECT \ ./path/to/dSYMs
-
- Android (Proguard Mappings):
- If using code obfuscation, retrieve Proguard mappings from EAS Build artifacts (in
android/app/build/outputs/mapping/). -
Upload to Sentry:
sentry-cli upload-proguard \ --org YOUR_ORG \ --project YOUR_PROJECT \ ./path/to/mapping.txt
- If using code obfuscation, retrieve Proguard mappings from EAS Build artifacts (in
- iOS (dSYMs):
-
Automate in CI/CD: See the CI/CD section below for integrating source map and artifact uploads into your pipeline.
- Best Practices:
- Ensure the
releasename in Sentry matches your app version (e.g.,my-app@1.0.0). - Upload source maps and artifacts for every build to ensure readable stack traces.
- Store
SENTRY_AUTH_TOKENsecurely in your CI/CD environment variables.
- Ensure the
4. CI/CD Configuration with Expo
Expo apps typically use EAS Build in CI/CD pipelines (e.g., GitHub Actions, CircleCI). Below is a guide to configure Sentry in a CI/CD pipeline, focusing on differences from a standard React Native setup.
- Set Up GitHub Actions:
Create a
.github/workflows/build.ymlfile for your pipeline:
name: Build and Deploy with Sentry
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm install
- name: Install EAS CLI
run: npm install -g eas-cli
- name: Install Sentry CLI
run: npm install -g @sentry/cli
- name: Configure EAS
env:
EXPO_TOKEN: $
run: eas login
- name: Build iOS and Android
env:
EXPO_TOKEN: $
SENTRY_AUTH_TOKEN: $
SENTRY_ORG: your-org
SENTRY_PROJECT: your-project
APP_VERSION: $ # Or use package.json version
run: |
eas build --platform all --profile production --non-interactive
# Export bundle with source maps
expo export --dev --sourcemaps
# Create Sentry release
sentry-cli releases new my-app@$APP_VERSION
# Upload source maps
sentry-cli sourcemaps upload \
--org $SENTRY_ORG \
--project $SENTRY_PROJECT \
--release my-app@$APP_VERSION \
./dist
# Upload dSYMs (iOS)
sentry-cli upload-dif \
--org $SENTRY_ORG \
--project $SENTRY_PROJECT \
./path/to/dSYMs
# Upload Proguard mappings (Android, if applicable)
sentry-cli upload-proguard \
--org $SENTRY_ORG \
--project $SENTRY_PROJECT \
./path/to/mapping.txt
# Finalize release
sentry-cli releases finalize my-app@$APP_VERSION
- name: Submit to App Store/Play Store (Optional)
run: eas submit --platform all
- Store Secrets:
- Add the following secrets in your GitHub repository settings:
EXPO_TOKEN: Generate viaeas loginand copy the token.SENTRY_AUTH_TOKEN: Generate from Sentry’s account settings.SENTRY_ORGandSENTRY_PROJECT: Your Sentry organization and project slugs.
- Add the following secrets in your GitHub repository settings:
- Key CI/CD Differences for Expo:
- EAS Build: Use
eas buildinstead of direct Xcode/Gradle builds. This handles native compilation and artifact generation. - Source Map Export: Use
expo export --sourcemapsto generate bundles and source maps, as Expo manages the bundling process. - Artifact Retrieval: Download dSYMs and Proguard mappings from EAS Build artifacts (via
eas build:downloador the EAS dashboard). - Release Creation: Automate Sentry release creation with
sentry-cli releases newto match your app version. - Dynamic Versioning: Use
github.shaorpackage.jsonversion for thereleasefield to ensure unique releases per build.
- EAS Build: Use
- Best Practices for CI/CD:
- Run
expo exportin the same environment as your EAS Build to ensure bundle consistency. - Use
--non-interactivefor EAS commands in CI/CD to avoid prompts. - Cache dependencies (e.g.,
npm cache) to speed up builds. - Test your pipeline with a preview build before deploying to production.
- Monitor Sentry’s quota usage in CI/CD logs to avoid exceeding limits.
- Run
5. Test Your Integration
-
Test JavaScript Errors: Add a test button to trigger a JavaScript error:
import * as Sentry from '@sentry/react-native'; function TestSentry() { return ( <Button title="Test Sentry" onPress={() => { throw new Error('Test Sentry Error'); }} /> ); } - Test Native Crashes:
- Native crashes require an EAS Build or custom dev client (not Expo Go).
-
Trigger a native crash using:
import * as Sentry from '@sentry/react-native'; Sentry.nativeCrash(); -
Build and run the app via EAS:
eas build --platform ios --profile production - Verify the crash in Sentry’s dashboard.
- Test in Expo Go:
- Expo Go supports JavaScript error tracking but not native crashes.
- Use
expo startand test JavaScript errors to verify basic setup.
- Best Practices for Testing:
- Test JavaScript errors in Expo Go during development.
- Test native crashes in a production build via EAS.
- Verify source maps and symbolication by checking stack traces in Sentry.
- Simulate offline scenarios to ensure events are cached and synced.
6. Additional Expo-Specific Configurations
-
Update
app.json: Ensure yourapp.jsonorapp.config.jsincludes the correct version and build settings:{ "expo": { "name": "MyApp", "slug": "my-app", "version": "1.0.0", "sentry": { "hooks": true } } }- The
sentry.hooksfield enables Sentry’s auto-instrumentation during EAS builds.
- The
- Performance Monitoring:
- The
ReactNativeTracingintegration works the same as in the React Native guide. - For React Navigation, ensure the navigation ref is registered (see previous
App.tsxexample). - Monitor App Start and Slow/Frozen Frames in Sentry, as these are critical for mobile UX.
- The
-
User Feedback: Add a feedback form, as shown previously:
import * as Sentry from '@sentry/react-native'; function showFeedbackForm() { Sentry.showReportDialog({ eventId: Sentry.lastEventId(), title: 'Report an Issue', }); } - Best Practices:
- Use EAS Build for production to ensure native crash reporting and performance tracking.
- Sync your
app.jsonversion with Sentry’sreleasefield. - Customize the feedback form to match your app’s branding.
7. Monitor and Optimize
- Track Release Health:
-
Use Sentry’s release tracking to monitor crash-free sessions:
sentry-cli releases new my-app@1.0.0 sentry-cli releases set-commits --commit "repo@commit" my-app@1.0.0 sentry-cli releases finalize my-app@1.0.0 -
Automate this in your CI/CD pipeline (see GitHub Actions example).
-
- Optimize Event Volume:
-
Set
tracesSampleRateto a lower value (e.g.,0.2) in production:Sentry.init({ tracesSampleRate: 0.2, }); -
Ignore low-value errors:
Sentry.init({ ignoreErrors: ['NetworkError', 'TimeoutError'], });
-
- Best Practices:
- Regularly review Sentry’s dashboard to resolve or ignore issues.
- Use Discover to analyze crashes by device, OS, or app version.
- Monitor EAS Build logs for errors during source map or artifact uploads.
Summary of Expo and CI/CD Differences
- Managed Workflow: Use EAS Build or custom dev clients for native crash reporting, as Expo Go is limited to JavaScript errors.
- Source Maps: Generate with
expo export --sourcemapsand upload via Sentry CLI. - Native Artifacts: Download dSYMs and Proguard mappings from EAS Build artifacts for symbolication.
- CI/CD: Use EAS CLI in pipelines (e.g., GitHub Actions) to automate builds, source map uploads, and release creation.
- Versioning: Sync
app.jsonversion with Sentry’sreleasefield for accurate release tracking. - Testing: Test JavaScript errors in Expo Go, but use EAS builds for native crashes and performance metrics.
- Security: Store
SENTRY_DSN,SENTRY_AUTH_TOKEN, andEXPO_TOKENin environment variables or CI secrets.
Next Steps
- Refer to the Sentry Expo Documentation for additional details.
- Explore EAS Build’s advanced features, like custom build hooks, for deeper Sentry integration.
- If you need help with specific CI/CD setups (e.g., CircleCI, Bitrise) or troubleshooting, let me know!
Comments