react-brain
Browse decisions
React & language foundations 3App architecture 11UI 13Platform & native 9Build, test, observe, secure 6AI in React apps 3stack composerdecision recordscensusstaleness benchnewsletterarchitecturechangelogmethodologyroadmap

entriestooling-ops · verified 2026-09-24 · react + react-native

Crash reporting, monitoring & observability

reviewedconfidence: mediumthis tier holds 71% on the public scorecard (7/20 graded · 0 overturned) →

related decisions: ai-devtools · ota · meta-frameworks

cited by: ota

re-verified 8× — 2026-09-24 · 2026-09-21 · 2026-09-10 · 2026-09-01 · 2026-08-18 · 2026-07-13 +2 · changelog

recommendation

Sentry for crash + performance monitoring on React and React Native (v8 of the RN SDK catches pre-bootstrap crashes); add app/route-level error boundaries and wire them to it at the production stage.

  • on Expo (SDK 55+) and want build/OTA regression tracing or per-route time-to-interactive → EAS Observe (add alongside Sentry; expo-observe + markInteractive(); needs a new binary; does not capture native crashes)
  • already on Firebase → Firebase Crashlytics (for crashes; add Sentry or EAS Observe for performance)
  • already on Bugsnag → Bugsnag (keep it for crashes; 9.0.0 is a new major, read its changelog before upgrading)
  • need component-level profiling of a RELEASE build → @callstack/inspector (0.1.x; dev-mode profiles misrepresent production)
  • profiling React on the web or following an older runbook → React DevTools 8.0 (browser Performance panel React tracks; the Timeline tab is gone)
  • day-to-day React Native inspection (network, storage, performance) → Rozenite (inside React Native DevTools; Expo SDK 52+ / RN 0.76+ / Re.Pack 5.2+)

Options & tradeoffs

the field considered — and why each one isn’t the default here

optiontradeoffevidence
Sentry (v8)Crash + performance monitoring on both platforms; v8 of @sentry/react-native captures crashes before RN bootstraps via sentry.options.json (the 'instant death on TestFlight' class). @sentry/react-native 8.28.0 (2026-09-24, verified vs npm); web uses @sentry/react 11.0.0 (2026-09-23, verified vs npm).ships in 16/34
EAS Observe (Expo)Production performance monitoring for Expo apps: real-session startup/TTI/bundle-load/update-apply metrics with every build and OTA update as a marker, plus per-route TTI. Not a crash reporter — no native crashes, keep Sentry alongside. GA 2026-08-25 (verified vs the GA post); expo-observe 57.0.24 (2026-09-24, verified vs npm). See note: EAS OBSERVE.
Firebase Crashlytics / BugsnagEstablished crash reporting; neither gives Observe-style build/update attribution. @react-native-firebase/crashlytics 26.4.0 (2026-09-05), @bugsnag/react-native 9.0.0 (2026-09-22, new major; both verified vs npm).ships in 2/34
Rozenite (Callstack incubator)Plug-and-play panels inside React Native DevTools (network/storage/performance, custom type-safe panels), no extra window or server; plugins are auto-disabled in production builds. rozenite 2.4.0 (2026-09-03, verified vs npm). See note: ROZENITE.
React DevTools 8.08.0.0 (2026-09-08, verified vs CHANGELOG) removes the Timeline profiler tab — React profiling moves to the browser Performance panel's React tracks — and turns the Suspense tab on by default. A runbook that says 'open the Timeline tab' is out of date. See note: REACT DEVTOOLS 8.0.
@callstack/inspectorReact-level component profiling in RELEASE builds via React DevTools, zero native changes — the honest lens, since dev-mode profiling misrepresents production. 0.1.1 (2026-05-22, verified vs npm): very young.803/wk

evidence: npm weekly downloads (signals snapshot) · “ships in n/D” = adoption across the production-app census, honest denominators

npm weekly downloads (from the corpus's last signals run): @callstack/inspector 803

Verified notes

Observability is three questions, not one tool: did it crash, is it slow, and which release did it. Sentry holds the default because one SDK covers the first two on both platforms, and v8 of the RN SDK closed the classic blind spot of crashes before the JS bundle loads. Error boundaries are the collection points that turn an uncaught render error from a blank tree into a report, which is why the source scan flags production repos with none. It is a production-stage concern: a prototype does not need dashboards; a production app without them cannot see what users hit. EAS OBSERVE (2026-08-25 GA, verified vs the Expo GA post; open beta May→Aug): install expo-observe, wrap the root in <ObserveRoot> and call markInteractive(); it reports startup (cold/warm), time-to-interactive/time-to-render, bundle load and EAS Update download/apply times from real sessions, P50/P90/P99 across devices, plus JS errors and device context. Two things Sentry-style tools do not give: every build AND OTA update lands as a marker, so a regression traces to the release that caused it, and the Expo Router / React Navigation integration breaks time-to-interactive down per route. Metrics are queryable from the EAS CLI as JSON (there is an eas-observe Expo Skill for agent handoff). Pricing is per event, not per MAU: 100K events/mo free; Starter $19/mo and Production $199/mo each include 500K; $5 per million beyond; 90-day minimum retention. Floors: SDK 55+ for startup metrics, 56+ for per-route metrics, 57+ for JS error reporting (in preview); enabling it needs a new binary, not just config. It does not capture native crashes, and Expo's own guidance is to keep Sentry alongside. EXPO-OBSERVE SDK 58 SURFACE (2026-09-21, verified vs the Expo SDK 58 beta changelog): the error side grows — ObserveErrorBoundary and reportError, an errorHandlingEnabled option, Observe.registerIntegration, an expo-image integration, and Observe.clientId (the EAS client id stamped on every event) — and the `AppMetrics` export is DEPRECATED in favour of `Observe`. Beta-era tutorials use the old name, so a copied example now warns; the fix is a rename. Three smaller deprecations in the same release touch code observability setups tend to own: expo-file-system File.md5 → File.digest(), expo-modules-core NativeArrayBuffer → ArrayBuffer, and @expo/ui iOS backgroundOverlay → background. REACT DEVTOOLS 8.0 (2026-09-08, verified vs the React DevTools CHANGELOG): the Timeline profiler tab is removed and React profiling moves to the browser's Performance panel, which carries React tracks; the Suspense tab is on by default (see what caused a component to suspend); the browser Elements panel gains a React Element pane mapping the inspected DOM node to its component; <Activity> subtrees are shown and dimmed when hidden. ROZENITE (2026-09-10, verified vs the GitHub repo and v2.3.0 release notes; version re-checked 2026-09-24 vs npm): fills the gap between "React DevTools shows me the component tree" and "I need a whole APM". Works on Expo and bare RN across Metro and Re.Pack; Rozenite >=2.0 needs Expo SDK 52+ / RN 0.76+ / Re.Pack 5.2+. Reaches Lynx via rspeedy and RN Web via a browser extension (both experimental). About 656 stars, active since 2025-07 — young but past the prototype stage. Agent angle: `rozenite agent tap` streams plugin/runtime state to stdout, the same job the Reactotron MCP row in RB-E-AI-DEVTOOLS does, so on an RN project it serves both the human debugging surface and the agent one. CROSS-REFERENCES: RB-E-OTA owns staged rollout and rollback (the action side of Observe's attribution); RB-E-AI-DEVTOOLS owns agent-facing runtime inspection (Reactotron MCP); RB-E-META-FRAMEWORKS owns rendering strategy behind the web metrics. HISTORY: 2026-09-24 REOPENED: version receipts re-checked vs npm; Bugsnag 9.0.0 (2026-09-22) and the web Sentry SDK major (@sentry/react 11) recorded. 2026-09-21 REOPENED: expo-observe AppMetrics deprecated → Observe; SDK 58 error-reporting surface. 2026-07-10 GAP CLOSED: @callstack/inspector added (release-build profiling, verified vs npm).

Canonical reading

Editorial annotations on why each piece matters — the articles themselves are the originals; read them there.

How to find a Next.js memory leak in productionXabier Lameiro

Production heap-diagnosis methodology on a real case: three Next.js framework leaks between 15.5 and 16.2 (router LRU cache ignoring URL-key size — hundreds of MB proportional to unique routes; RSC streams retained on client disconnect, worst on Node 22/24; middleware timeout IDs never released), all fixed by 16.3.0. The durable half is the method — chart process.memoryUsage() against candidate variables (unique URLs, traffic, middleware) to match the growth SIGNATURE before assigning blame, then diff heap snapshots and read retainer chains (LRUNode / reactServerStream / TimeoutsManager name the culprits). Also: raising heap limits is a band-aid against a monotonic slope, and on serverless memory problems surface as latency, so profile that instead.

Bringing Lighthouse to the App: Core Web Vitals for React NativeBen Cripps (Indeed Engineering)

Adapts web Core Web Vitals (TTFF/TTI/FID) into a React Native performance hook with composite scoring, from a real ViewJob rollout. A durable blueprint for measuring (not just crash-reporting) RN performance in production.

The Hidden Cost of Hydration MismatchesIvan Akulov (3perf, perf consultant)

Web-side production-perf diagnosis from real consulting: a single hydration mismatch makes React recreate the DOM, and because LCP only tracks NEW elements, the remounted (font-swapped, larger) text re-triggers LCP at hydration time — green→red with no obvious cause. Durable lessons: keep server/client renders identical, scope unavoidable mismatches with Suspense, and know how the metric itself measures (the metric mechanics are the observability half — the rendering-strategy background lives in RB-E-META-FRAMEWORKS's readings). The web counterpart to the Indeed RN piece above.

Sources

The full explanation

The reviewed long-form essay behind this entry — the why, not a how-to. Also on GitHub.

About observability — three questions production must answer

Diataxis: Explanation. This page builds understanding of the monitoring landscape — the reasoning behind the picks. It is not a setup guide. CI gating is RB-E-DX; update delivery is RB-E-OTA; web rendering strategy behind the metrics is RB-E-META-FRAMEWORKS.

The one principle that organises everything: you can't fix what production won't tell you

Local testing answers "does it work here"; observability answers "what is it doing to users." The landscape stops being a vendor list once you see it as three distinct questions, each needing its own instrumentation:

  1. Did it crash? — error/crash reporting. Table stakes, and subtler than it looks on RN, where a JS exception, a native crash, and a startup crash before the JS loads are three different animals.
  2. Is it slow? — performance measurement. Needs metrics, not vibes: startup time, frame drops, interaction latency (the CWV-for-RN reading), and on web the hydration/LCP mechanics.
  3. Which release did it? — attribution. Mobile ships by store release and OTA update (RB-E-OTA); a regression is only actionable when telemetry names the build or update that introduced it.

Most teams buy tool #1 and believe they have all three.

The default, and why

Sentry for crash + performance monitoring (v8 catches pre-bootstrap crashes); add error boundaries and wire it up at the production stage.

Sentry earns the default by covering the most of questions 1–2 in one SDK on both platforms — and v8 fixed RN's classic blind spot: crashes before RN bootstraps (the "instant death on TestFlight" class) are now captured via sentry.options.json. Error boundaries are the collection points that make React errors reportable instead of blank screens — which is why the corpus's source-scan flags production repos with no boundary at all (an uncaught render error blanks the tree and tells you nothing). "Production stage" is honest calibration: a prototype doesn't need dashboards; a production app without them is flying blind.

The landscape, by question

Sentry (v8) — questions 1 and 2: crashes (JS + native + pre-bootstrap), tracing, release health; 8.17 added Turbo-Module tracking and Expo Router auto-instrumentation.

EAS Observe (Expo) — question 3, natively, plus much of question 2: real-session startup, time-to-interactive and update-apply metrics with every build and OTA update as a marker, so a regression traces to a specific build or OTA update. Generally available since 2026-08-25 (SDK 55+; per-route metrics on 56+; JS error reporting in preview on 57+). Two limits change how you adopt it: turning it on needs a new binary, and it does not capture native crashes — keep Sentry (or your existing reporter) alongside, as Expo itself advises.

Firebase Crashlytics / Bugsnag — established question-1 alternatives; Crashlytics is fine when you're already on Firebase.

@callstack/inspector — a gap-filler: React-level component profiling in release builds via React DevTools, no native changes. Dev-mode profiling lies about production; this is the honest lens. Very young (v0.1.x) — treat as experimental.

React DevTools 8.0 — the web profiling workflow moved: the Timeline profiler tab is gone (8.0.0, 2026-09-08) and React profiling now lives in the browser's Performance panel as React tracks. Guides that say "open the Timeline tab" predate it.

Rozenite — day-to-day RN inspection panels (network, storage, performance) inside React Native DevTools; plugins are disabled in production builds.

The measurement readings — Indeed's CWV-for-RN (build the metrics: TTFF/TTI/FID-analogues with composite scoring) and the 3perf hydration piece (web: one hydration mismatch re-creates the DOM and silently re-triggers LCP — know how the metric itself measures).

Tradeoffs and failure modes to name out loud

  • No error boundary in a production app. The corpus's absent-rule exists because it keeps being found: one uncaught render error blanks the whole tree, uncollected.
  • Crash reporting mistaken for performance monitoring. Zero crashes and 9-second cold starts coexist happily. Question 2 needs deliberate metrics, not an SDK's default dashboard.
  • Shipping OTA without attribution. Fast updates (RB-E-OTA) cut both ways: without build/update-level telemetry, a bad update is invisible until reviews arrive. Staged rollouts are only as good as the monitoring that decides go/no-go.
  • Profiling dev builds. Dev mode disables the optimizations that shape production behavior; release-build profiling (inspector) or production sampling is the truth.
  • Vendor lock via instrumentation sprawl. Route custom events through one thin wrapper; swapping SDKs later shouldn't mean touching every screen.

How it interacts with the rest of the stack

  • OTA (RB-E-OTA). Staged rollout + abort/rollback is an observability loop: Observe-class attribution is what makes the rollback decision data instead of panic.
  • DX (RB-E-DX). CI gates catch regressions before release; observability catches the ones that ship anyway. Same philosophy — mechanized feedback — different end of the pipeline.
  • Meta-frameworks (RB-E-META-FRAMEWORKS). Web metrics are rendering-strategy-shaped; hydration mismatches are a rendering bug that presents as a metrics mystery.
  • Security (RB-E-SECURITY). Crash/telemetry pipelines carry user data — scrubbing and data-minimization are part of wiring them, not an afterthought.

In one paragraph

Observability is three questions, not one tool: did it crash (Sentry v8, plus the error boundaries that make React errors collectable), is it slow (deliberate metrics — CWV-for-RN on native, hydration/LCP mechanics on web, release-build profiling when you need component truth), and which release did it (EAS Observe-class attribution across store builds and OTA updates). It's a production-stage concern that pairs with RB-E-OTA's staged rollouts — fast shipping without attribution is just fast guessing — and the cheapest first step is the one the corpus scans for: put an error boundary at the top of the tree and wire it to the reporter.


See also: RB-E-OTA (rollout/rollback is the action side of this loop), RB-E-DX (the pre-release half of mechanized feedback), RB-E-META-FRAMEWORKS (web rendering behind the metrics), RB-E-SECURITY (telemetry data hygiene).

Related in tooling-ops: build · testing · dx · security · ota