Articles · GuidesUpdated October 2026

Sentry catches the crash on its own. The part you have to arrange is a trace you can read.

Error tracking with Sentry means one SDK in your React Native and Expo project, after which crashes on phones you will never hold arrive in a dashboard with a stack trace, the device, and the last few things the person did. Sentry's own documentation says the capture side needs almost no help from you: unhandled JavaScript errors, unhandled promise rejections, native crashes, app hangs on Apple platforms, Android ANRs and a session per launch are all on by default. The step that goes wrong is the other one. A release build ships bytecode, so the trace is unreadable unless source maps were uploaded at the moment that build was made. If you are still working out what React Native is, start there and come back.

What follows is what the SDK takes without being asked, what it will not take until you ask, why the same crash is readable on your laptop and gibberish from TestFlight, who has to wire the upload into a project somebody else generated, and what the whole thing costs in money and in store paperwork. Every option name, default and figure below was read from Sentry's and Expo's own documentation on 17 October 2026.

Start here

The short version

Capture is the easy half. Symbolication is the half you own.

Install the SDK, keep the defaults, and you have a crash reporter that catches thrown errors, rejected promises, native crashes, frozen main threads and the breadcrumbs leading up to them. None of that needs configuration. It is the part of the job Sentry does for you.

The readable trace is a build time arrangement. Source maps have to be produced and uploaded by the same process that produces the release build, and matched to it by an id. Get that right once and every crash afterwards names a file and a line in your own code. Get it wrong and you collect perfectly delivered reports about a function called t at offset 41892, for as long as that version is in people's hands.

What does Sentry's React Native SDK actually capture?

More than people assume, and less than the marketing around error tracking suggests. The errors arrive through an integration that hooks React Native's own global handler, ErrorUtils. Two options control it and both default to true, one for unhandled errors and one for unhandled promise rejections. Sentry notes that rejection behaviour varies by JavaScript engine and keeps a separate page for it. Native crash handling is a different switch, also true by default, so a crash in Objective C or Java is reported as well, and a second integration follows an error across that boundary and collects the debug images needed to read the native frames.

Frozen apps are covered separately from crashes, and the platforms do not agree. On Apple platforms app hang tracking is on by default, and the threshold, which Sentry calls the app hang timeout interval, is two seconds. On Android, ANR detection on the JVM side is described as always on by default. The NDK based hang detection is a different feature, off by default, with a timeout of 5000 milliseconds when you enable it. Sessions are on too, because automatic session tracking defaults to true, and that is what produces a crash free rate rather than a raw count of errors.

Breadcrumbs are where this gets interesting for anyone who inherited a codebase. The breadcrumbs integration records console calls by default. It records XHR requests by default, and on mobile it leaves fetch off so the two do not duplicate each other. It records every event sent to Sentry. On mobile the native layer adds touch, navigation and app lifecycle breadcrumbs on top. The practical consequence is worth saying plainly: anything a previous developer left in a console.log, an email address, an order payload, a token, is attached to the next error report that goes out of the app. That is a five minute audit and nobody does it.

The things people worry about are off by default. Sending personal data is false by default, which is what otherwise adds IP address, cookies and user data to events. Screenshots are off. The view hierarchy attachment is off. Capturing failed HTTP requests as errors is off. Performance tracing does nothing at all until you set a traces sample rate or a sampler function, and timing spans for user interactions need both an opt in option and your root component wrapped. So a default install reports crashes. It does not watch your users, and it will not tell you why a screen is slow until you ask it to.

Sentry, default integrations for React Native, read 17 October 2026

Check yours

What arrives in Sentry before you configure anything

Tick what you were wondering about. The option names and defaults are the ones in Sentry's React Native documentation, read on 17 October 2026.

Nothing ticked. The short version: crashes, hangs and unhandled rejections are on, breadcrumbs are on, and anything that looks at the user or at performance is off until you ask for it.

Why is the stack trace from a real phone unreadable?

Because on your laptop something else is doing the work. Sentry says symbolication in development is handled directly by the Metro development server, which still has the original code, so nothing has to be uploaded and the problem stays invisible. A release build has no Metro. Expo's documentation says Hermes is its default JavaScript engine, and that an export or an update produces Hermes bytecode bundles along with their source maps. So the trace coming back from a TestFlight tester points into bytecode, and the only thing that can turn it back into your file names is a source map that was uploaded for that exact build.

Sentry's own source map page states the requirement without hedging: to get unminified stack traces for JavaScript code, source maps must be generated and uploaded. It also says the React Native SDK handles that automatically for iOS with Xcode and for Android with Gradle, provided you do not use custom values, and the documented way to get there is its wizard, which configures the build tooling on both platforms. The page gives 5.11.0 as the minimum SDK version for those instructions, which matters if you were handed a project that has been sitting for a year.

Two switches explain most missing maps. One is an environment variable, SENTRY_DISABLE_AUTO_UPLOAD, which turns the upload off and which build pipelines sometimes set to keep builds quiet. The other is the Expo config plugin, whose disable option gets baked into the native projects when prebuild runs, so the setting can be sitting in your app config rather than in any build script. Matching a bundle to its map is handled by debug ids, which is why Sentry has you build the Metro config with its own helper, getSentryExpoConfig: it is what gives bundles and maps the same unique id.

One more thing to know before you upgrade anything. Expo documents that Hermes bytecode can change between versions, so an update built against one runtime is not safe to serve to another, which is what the runtime version field in your app config exists to prevent. That puts your error tracking and your upgrade schedule in the same conversation, because a bump to the framework changes both the bytecode and the maps that read it. Engine and tooling changes of that kind show up in the Expo SDK release notes, which is the only place worth reading them.

Sentry, source maps for React Native, read 17 October 2026

The same crash, in three places it can come from

What you are looking atRunning on your laptopA release build, TestFlight or PlayAn over the air update
What the JavaScript isServed live by MetroHermes bytecode inside the binaryHermes bytecode inside the update bundle
Who makes the trace readableThe Metro development serverSource maps uploaded when that build was madeSource maps uploaded for that specific update
An upload has to happenNoYesYes
Automatic once the wizard has runNot applicableYes for iOS with Xcode and Android with Gradle, if you use no custom valuesNo, Expo documents a separate command you run after eas update
Where the auth token has to beNot neededA local env file, or a secret in whatever builds your releaseWherever you run the upload command
What you see if you skip itReadable traces, so the problem stays hiddenMinified names and bytecode offsetsMinified names, and no way to tell which update it was

Who has to wire this up in a project you did not type?

You do, and it is an afternoon rather than a project. The package is @sentry/react-native, installed through the Expo installer so the version matches your SDK. Sentry's Expo setup page gives Expo SDK 50 as the floor, and says the older sentry-expo package covers SDK 49 and earlier and is deprecated. That one line saves a lot of confusion, because plenty of guides online still tell you to install sentry-expo, and following them in a current project gets you a package that does not belong there. The wizard handles the rest: dependencies, the Metro config, the init call, and the Xcode and Gradle build steps that do the uploading.

The auth token is what actually breaks on a handover. Sentry documents keeping it in a local environment file that is never committed, and says to add it as an EAS secret instead for EAS builds. Expo's guide says the same thing from its side: set the token in the build environment, marked sensitive, and source maps then upload with no further work. If your traces were readable last month and are minified now, check the token before you touch anything else. It is the piece most likely to have moved when somebody changed the pipeline or left the team.

Over the air updates are the one genuinely manual step, and it is the step everybody misses. Expo's guide has you run the upload yourself after publishing an update, with a command called sentry-expo-upload-sourcemaps pointed at the export directory, and shows the publish and the upload chained into a single command so there is no window in which you forget. The name still carries the old sentry-expo prefix, which is confusing given the package itself is deprecated, but it is what Expo's current guide tells you to run. The guide also gives a snippet that reads the update module and tags every event with the update id, whether the launch came from the embedded bundle, the update group and a debug url. Without those tags you can see that something crashed and have no idea which update was running.

Then decide where this lives permanently. The upload belongs inside whatever produces your release build, which means the question is not technical but organisational: who owns that pipeline now. Settle it before the first external tester, not after, because the builds that crash are the ones already in other people's hands, and the maps for them cannot be produced later. If the next thing on your list is publishing to the App Store, do the Sentry wiring first and submit second.

What does error tracking cost you, in money and in paperwork?

Sentry's pricing page, read on 17 October 2026, lists a free Developer plan for one user with 5k errors and a 30 day lookback, and a Team plan at $29 a month billed monthly, or $26 a month billed annually, for unlimited users with 50k errors and up to a 90 day lookback. Additional events are charged on top. The plan table does not print a period beside those allowances, so treat them as the figures to check against your own usage page rather than as a promise. For a first app the free plan is usually plenty, and the limit that bites first is not the error count but the lookback: on the free plan a crash from two months ago is simply gone.

The paperwork cost is the one people forget. A crash reporter sends data off the device, and both stores make you answer for data collected by code you did not write. That means the App Privacy questions in App Store Connect, where crash data is the usual answer, and the Data safety form in Play Console, where it is crash logs and diagnostics. The defaults are on your side here, since personal data, screenshots and the view hierarchy are all off until you switch them on. The exposure is breadcrumbs, because console calls are recorded by default, so the honest answer to what your app collects depends on what the last person to touch the code was logging.

Set against that, the thing error tracking saves you is the worst cost in mobile, which is a bug you cannot reproduce. A release without crash reporting is one where the only signal is a one star review saying the app closes. Next to the store fees and the build time in what it costs to publish an app, a free Sentry project and an afternoon of wiring is the cheapest line on the page.

Where this lands if Newly generated your app

Nothing above changes because an agent wrote the code. The project is a real React Native and Expo project that you own, the crash is in your code either way, and Sentry has no idea how the file got there. What changes is only who presses which button. Newly uploads iOS builds to TestFlight, publishes to Google Play internal testing and builds a standalone Android APK, and it does not submit to the App Store for you, because Apple requires the owner of the content to submit. It is $25 a month, with no free plan.

Two practical notes for that setup. First, check before you install: search the repo for @sentry/react-native and for an existing init call, because adding a second one is a confusing afternoon. Second, the two way GitHub sync is what makes this easy to own. You can install the SDK, add the plugin and commit the Metro config change in the repository, or ask the agent to do it, and the change lives in the same place either way.

The honest limit is the upload, and it is worth being clear about it. A source map is only useful if it was produced by the same process that produced the binary, and matched to it. So the question to answer on day one is where your release builds come from and whether that step runs the upload. Generating an app does not answer that for you, and neither does installing the SDK. It is one decision, it takes ten minutes, and it is the difference between a crash report that names a line in your code and one that names a letter.

Questions people ask about error tracking with Sentry

Unhandled JavaScript errors and unhandled promise rejections, through an integration that hooks React Native's own global handler. Native crashes, because native crash handling defaults to true. App hangs on Apple platforms, with a two second threshold by default, and Android ANR detection on the JVM side, which Sentry's own page describes as always on by default. A session per app launch, because automatic session tracking defaults to true. And breadcrumbs, including console calls, XHR requests, and touch, navigation and app lifecycle events from the native layer on mobile. Read on 17 October 2026.

Describe the app, then wire the crash reports before the testers arrive

Install the SDK, confirm the source maps upload on a real release build, and tag your updates. After that every crash report you get points at a file and a line you can open.

Start building