|
| 1 | +--- |
| 2 | +title: Sentry Setup |
| 3 | +description: How to setup Sentry in your app. |
| 4 | +head: |
| 5 | + - tag: title |
| 6 | + content: Sentry Setup | React Native / Expo Starter |
| 7 | +--- |
| 8 | + |
| 9 | +import CodeBlock from '../../../components/code.astro'; |
| 10 | +import { Steps } from '@astrojs/starlight/components'; |
| 11 | + |
| 12 | +Sentry is one of the most popular solution for error reporting in the javascript ecosystem and has a great integration with Expo, we have been using it for a while and it has been working very well. |
| 13 | + |
| 14 | +The starter kit did not come with Sentry pre-configured, but it's very easy to setup and this guide will walk you through the process. |
| 15 | + |
| 16 | +## Install and configure Sentry |
| 17 | + |
| 18 | +<Steps> |
| 19 | +1. Create a new [Sentry account](https://sentry.io/signup/) if you don't have one already. Once logged in, create a new project for your React Native app. |
| 20 | + |
| 21 | +2. During project creation, pay close attention to and note down the following important details: |
| 22 | + |
| 23 | + - Organization slug |
| 24 | + - Project name |
| 25 | + - DSN |
| 26 | + |
| 27 | + we will use those details next to configure the Sentry SDK in your app. |
| 28 | + |
| 29 | +3. Now you need also to generate a new Auth Token so you can use it to upload source maps to Sentry. To generate a new Auth Token you need to go to Developer [Settings > Auth Tokens](https://sentry.io/settings/auth-tokens/) and create a new token. |
| 30 | + |
| 31 | + - Copy and securely store the generated token. You'll need this for configuring source map uploads. |
| 32 | + |
| 33 | +4. At this point, you should have the following environment variables that need to be added to your `.env` files: |
| 34 | + |
| 35 | + ```bash |
| 36 | + SENTRY_ORG=your_sentry_organization_slug |
| 37 | + SENTRY_PROJECT=your_sentry_project_name |
| 38 | + SENTRY_DSN=your_sentry_dsn |
| 39 | + ``` |
| 40 | + |
| 41 | + :::note |
| 42 | + You can use the same Sentry configuration for all app variants (development, staging, production) as Sentry allows you to filter errors by app ID or package name in the dashboard. This simplifies setup and management while still providing the ability to distinguish between different environments. |
| 43 | + ::: |
| 44 | + |
| 45 | + It's crucial to add these variables to `env.js` for validation. `SENTRY_ORG` and `SENTRY_PROJECT` should be added as build-time variables, while `SENTRY_DSN` should be added as a client variable. |
| 46 | + |
| 47 | + Update your `env.js` file as follows: |
| 48 | + |
| 49 | + ```js title='env.js' |
| 50 | + // ... existing imports and configurations |
| 51 | + |
| 52 | + const client = z.object({ |
| 53 | + // ... other client env vars |
| 54 | + SENTRY_DSN: z.string().min(1, 'SENTRY_DSN is required'), |
| 55 | + }); |
| 56 | + |
| 57 | + const buildTime = z.object({ |
| 58 | + // ... other build-time env vars |
| 59 | + SENTRY_ORG: z.string().min(1, 'SENTRY_ORG is required'), |
| 60 | + SENTRY_PROJECT: z.string().min(1, 'SENTRY_PROJECT is required'), |
| 61 | + }); |
| 62 | + |
| 63 | + const _clientEnv = { |
| 64 | + // ... other client env vars |
| 65 | + SENTRY_DSN: process.env.SENTRY_DSN, |
| 66 | + }; |
| 67 | + |
| 68 | + const _buildTimeEnv = { |
| 69 | + // ... other build-time env vars |
| 70 | + SENTRY_ORG: process.env.SENTRY_ORG, |
| 71 | + SENTRY_PROJECT: process.env.SENTRY_PROJECT, |
| 72 | + }; |
| 73 | + |
| 74 | + // ... rest of the file |
| 75 | + ``` |
| 76 | + |
| 77 | + :::note |
| 78 | + The `SENTRY_AUTH_TOKEN` should not be added to the `.env` file as it's sensitive information that shouldn't be exposed or pushed to version control. Instead, add it as an EAS secret using the [Expo dashboard](https://expo.dev/accounts/[account]/projects/[project]/secrets) or the EAS CLI: |
| 79 | + |
| 80 | + ```bash |
| 81 | + eas secret:create --scope your-project-name --name SENTRY_AUTH_TOKEN --value your-token-value --type string |
| 82 | + ``` |
| 83 | + |
| 84 | + This ensures that your Sentry authentication token remains secure while still being accessible during the build process. |
| 85 | + ::: |
| 86 | + |
| 87 | +5. Now you can install the Sentry SDK in your project. |
| 88 | + |
| 89 | + ```bash |
| 90 | + npm install @sentry/react-native |
| 91 | + ``` |
| 92 | + |
| 93 | +6. Add Sentry plugin config to your `app.config.ts` file. |
| 94 | + |
| 95 | + ```tsx title='app.config.ts' |
| 96 | + // rest of the file |
| 97 | + |
| 98 | + import { ClientEnv, Env } from './env'; |
| 99 | + |
| 100 | + export default ({ config }: ConfigContext): ExpoConfig => ({ |
| 101 | + ...config, |
| 102 | + // rest of the config |
| 103 | + |
| 104 | + plugins: [ |
| 105 | + // rest of the plugins |
| 106 | + [ |
| 107 | + '@sentry/react-native/expo', |
| 108 | + { |
| 109 | + url: 'https://sentry.io/', |
| 110 | + organization: Env.SENTRY_ORG, |
| 111 | + project: Env.SENTRY_PROJECT, |
| 112 | + note: 'Ensure you set the SENTRY_AUTH_TOKEN as an environment variable to authenticate with Sentry. Do not add it to the .env file. Instead, add it as an EAS secret or as an environment variable in your CI/CD pipeline for security.', |
| 113 | + // If you are using a self-hosted instance, update the value of the url property |
| 114 | + // to point towards your self-hosted instance. For example, https://self-hosted.example.com/. |
| 115 | + }, |
| 116 | + ], |
| 117 | + ], |
| 118 | + }); |
| 119 | + ``` |
| 120 | + |
| 121 | +7. Update your metro config to inject debug ID intro your source maps |
| 122 | + |
| 123 | + ```js title='metro.config.js' |
| 124 | + /* eslint-env node */ |
| 125 | + // this replaces `const { getDefaultConfig } = require('expo/metro-config');` |
| 126 | + const { getSentryExpoConfig } = require('@sentry/react-native/metro'); |
| 127 | + const { withNativeWind } = require('nativewind/metro'); |
| 128 | + |
| 129 | + const config = getSentryExpoConfig(__dirname); |
| 130 | + |
| 131 | + module.exports = withNativeWind(config, { input: './global.css' }); |
| 132 | + ``` |
| 133 | + |
| 134 | +8. Now you are ready to initialize Sentry in your app. |
| 135 | + Create a new file `src/core/sentry.ts` and add the following code: |
| 136 | + |
| 137 | + ```tsx title='src/core/sentry.ts' |
| 138 | + import { useNavigationContainerRef } from 'expo-router'; |
| 139 | + import { useEffect } from 'react'; |
| 140 | + import * as Sentry from '@sentry/react-native'; |
| 141 | + import { Env } from '@env'; |
| 142 | + |
| 143 | + const routingInstrumentation = new Sentry.ReactNavigationInstrumentation(); |
| 144 | + |
| 145 | + export const initSentry = () => { |
| 146 | + Sentry.init({ |
| 147 | + dsn: Env.SENTRY_DSN, |
| 148 | + // debug: Env.APP_ENV === 'development', |
| 149 | + integrations: [ |
| 150 | + new Sentry.ReactNativeTracing({ |
| 151 | + routingInstrumentation, |
| 152 | + enableNativeFramesTracking: true, |
| 153 | + // ... |
| 154 | + }), |
| 155 | + ], |
| 156 | + }); |
| 157 | + }; |
| 158 | + |
| 159 | + export const useSentryNavigationConfig = () => { |
| 160 | + const navigationRef = useNavigationContainerRef(); |
| 161 | + |
| 162 | + useEffect(() => { |
| 163 | + if (navigationRef) { |
| 164 | + routingInstrumentation.registerNavigationContainer(navigationRef); |
| 165 | + } |
| 166 | + }, [navigationRef]); |
| 167 | + }; |
| 168 | + ``` |
| 169 | + |
| 170 | + Then, initialize Sentry and configure it with navigation in your `src/app/_layout.tsx` file: |
| 171 | + |
| 172 | + ```tsx title='src/app/_layout.tsx' |
| 173 | + import { initSentry, useSentryNavigationConfig } from '@/core/sentry'; |
| 174 | + import * as Sentry from '@sentry/react-native'; |
| 175 | + |
| 176 | + initSentry(); |
| 177 | + |
| 178 | + function RootLayout() { |
| 179 | + useSentryNavigationConfig(); |
| 180 | + |
| 181 | + return ( |
| 182 | + <Providers> |
| 183 | + <Stack> |
| 184 | + <Stack.Screen name="(app)" options={{ headerShown: false }} /> |
| 185 | + <Stack.Screen name="onboarding" options={{ headerShown: false }} /> |
| 186 | + ... |
| 187 | + </Stack> |
| 188 | + </Providers> |
| 189 | + ); |
| 190 | + } |
| 191 | + |
| 192 | + // Wrap your app with Sentry |
| 193 | + export default Sentry.wrap(RootLayout); |
| 194 | + ``` |
| 195 | + |
| 196 | + This setup will enable Sentry error tracking and performance monitoring in your app. |
| 197 | + |
| 198 | +9. One last thing is to add Apple privacy manifest to prevent any issues with Apple. |
| 199 | + Create a new file `apple-privacy-manifest.json` and add the following code: |
| 200 | + |
| 201 | + ```json title='apple-privacy-manifest.json' |
| 202 | + { |
| 203 | + "NSPrivacyCollectedDataTypes": [ |
| 204 | + { |
| 205 | + "NSPrivacyCollectedDataType": "NSPrivacyCollectedDataTypeCrashData", |
| 206 | + "NSPrivacyCollectedDataTypeLinked": false, |
| 207 | + "NSPrivacyCollectedDataTypeTracking": false, |
| 208 | + "NSPrivacyCollectedDataTypePurposes": [ |
| 209 | + "NSPrivacyCollectedDataTypePurposeAppFunctionality" |
| 210 | + ] |
| 211 | + }, |
| 212 | + { |
| 213 | + "NSPrivacyCollectedDataType": "NSPrivacyCollectedDataTypePerformanceData", |
| 214 | + "NSPrivacyCollectedDataTypeLinked": false, |
| 215 | + "NSPrivacyCollectedDataTypeTracking": false, |
| 216 | + "NSPrivacyCollectedDataTypePurposes": [ |
| 217 | + "NSPrivacyCollectedDataTypePurposeAppFunctionality" |
| 218 | + ] |
| 219 | + }, |
| 220 | + { |
| 221 | + "NSPrivacyCollectedDataType": "NSPrivacyCollectedDataTypeOtherDiagnosticData", |
| 222 | + "NSPrivacyCollectedDataTypeLinked": false, |
| 223 | + "NSPrivacyCollectedDataTypeTracking": false, |
| 224 | + "NSPrivacyCollectedDataTypePurposes": [ |
| 225 | + "NSPrivacyCollectedDataTypePurposeAppFunctionality" |
| 226 | + ] |
| 227 | + } |
| 228 | + ], |
| 229 | + "NSPrivacyAccessedAPITypes": [ |
| 230 | + { |
| 231 | + "NSPrivacyAccessedAPIType": "NSPrivacyAccessedAPICategoryUserDefaults", |
| 232 | + "NSPrivacyAccessedAPITypeReasons": ["CA92.1"] |
| 233 | + }, |
| 234 | + { |
| 235 | + "NSPrivacyAccessedAPIType": "NSPrivacyAccessedAPICategorySystemBootTime", |
| 236 | + "NSPrivacyAccessedAPITypeReasons": ["35F9.1"] |
| 237 | + }, |
| 238 | + { |
| 239 | + "NSPrivacyAccessedAPIType": "NSPrivacyAccessedAPICategoryFileTimestamp", |
| 240 | + "NSPrivacyAccessedAPITypeReasons": ["C617.1"] |
| 241 | + } |
| 242 | + ] |
| 243 | + } |
| 244 | + ``` |
| 245 | + |
| 246 | + Then add it to your `app.config.ts` |
| 247 | + |
| 248 | + ```ts title='app.config.ts' |
| 249 | + import applePrivacyManifest from './apple-privacy-manifest.json'; |
| 250 | + export default ({ config }: ConfigContext): ExpoConfig => ({ |
| 251 | + ...config, |
| 252 | + // rest of the config |
| 253 | + ios: { |
| 254 | + // rest of ios config |
| 255 | + privacyManifests: applePrivacyManifest, |
| 256 | + }, |
| 257 | + }); |
| 258 | + ``` |
| 259 | + |
| 260 | + Read more about [Apple Privacy Manifest and sentry](https://docs.sentry.io/platforms/react-native/data-management/apple-privacy-manifest/) |
| 261 | + |
| 262 | +10. Now you are ready to test Sentry integration. Follow these steps to ensure errors are being reported correctly: |
| 263 | + |
| 264 | + 1. Run the prebuild command for your project. |
| 265 | + 2. Launch the app in a simulator or on a physical device. |
| 266 | + 3. Use the following code snippet to add error-triggering buttons to your app: |
| 267 | + |
| 268 | + ```tsx |
| 269 | + import React from 'react'; |
| 270 | + import { View, Button } from 'react-native'; |
| 271 | + import * as Sentry from '@sentry/react-native'; |
| 272 | + |
| 273 | + const SentryTestComponent = () => { |
| 274 | + const throwJSError = () => { |
| 275 | + throw new Error('Test JavaScript Error for Sentry'); |
| 276 | + }; |
| 277 | + |
| 278 | + const triggerNativeError = () => { |
| 279 | + Sentry.nativeCrash(); |
| 280 | + }; |
| 281 | + |
| 282 | + return ( |
| 283 | + <View> |
| 284 | + <Button title="Trigger JS Error" onPress={throwJSError} /> |
| 285 | + <Button title="Trigger Native Error" onPress={triggerNativeError} /> |
| 286 | + </View> |
| 287 | + ); |
| 288 | + }; |
| 289 | + |
| 290 | + export default SentryTestComponent; |
| 291 | + ``` |
| 292 | + |
| 293 | + 4. Implement this component in your app and interact with the buttons. |
| 294 | + 5. Check your Sentry dashboard to verify that the errors are being reported correctly (make sure to wait a little bit for the errors to appear). |
| 295 | + |
| 296 | + Remember to remove or disable these test buttons before releasing your app to production. |
| 297 | + |
| 298 | +</Steps> |
| 299 | + |
| 300 | +## More Resources |
| 301 | + |
| 302 | +- [Expo Sentry](https://docs.expo.dev/guides/using-sentry/) |
| 303 | +- [Sentry Documentation](https://docs.sentry.io/platforms/react-native/manual-setup/expo/) |
0 commit comments