Observability Best Practices
A condensed summary of the 25 most important best practices drawn from every page in this section.
Search across all documentation pages
A condensed summary of the 25 most important best practices drawn from every page in this section.
Know the four signals: Crashes/fatals, handled errors, performance transactions, and product analytics - one vendor rarely replaces all four.
Tag every report with release identity: Native version+build, otaUpdateId, runtimeVersion, and channel - triage without reproducing on device.
Generate sessionId on cold start: Rotate on logout - same lifecycle discipline as Mobile Auth Basics tokens.
Attach route to crashes and logs: Expo Router pathname beats component display names - refactors rename components, routes stay stable.
Separate native crashes from JS errors: Different symbolication pipelines - Hermes maps and iOS dSYM / Android ProGuard are all required.
Chain ErrorUtils handlers: Never replace the previous global handler wholesale - dev redbox and SDK integrations depend on chaining.
Initialize Sentry before routes mount: Earliest _layout or index.js side effect - late init misses startup failures.
Upload source maps on every EAS production build: Unsymbolicated stacks are a release blocker, not a nice-to-have.
Set Sentry dist to OTA update id: Distinguish JS regressions from native regressions on the same store version.
Enable native crash capture: @sentry/react-native native modules - JS-only wrappers miss SIGABRT and OOM kills.
Cap breadcrumbs and log buffers: Unbounded rings OOM on chatty screens - drop debug first under pressure.
Batch structured logs; ship on foreground: Per-line HTTPS wastes battery - flush on active and best-effort on background.
Never log tokens, emails, or card data: Hash user ids; strip PII in beforeSend and analytics sanitize().
Gate analytics behind explicit consent: Separate toggles for crash reporting vs product analytics - legal owns the policy, engineering implements gates.
Request ATT only when needed on iOS: Align NSUserTrackingUsageDescription with actual cross-app tracking - vague copy fails review.
Reset analytics identity on logout: segment.reset() / Amplitude reset() alongside secure store clearing.
Use stable analytics event names: checkout_completed not completeCheckout - renames break year-over-year charts.
Sample production traces at 10–20%: 100% capture overwhelms cost; 100% on checkout/payment routes is fine.
Instrument navigation at the router layer: One navigation span per pathname - not per leaf useEffect.
Propagate trace headers on API calls: sentry-trace or W3C traceparent - mobile-only latency hides backend blame.
Define crash-free sessions SLO with session rules: Align with Sentry session tracking - exclude dev and preview environments from production numerators.
Track OTA apply success explicitly: Silent fetchUpdateAsync failures erode trust - measure check → download → apply → next-launch updateId.
Pair cold start SLO with reference device: p95 on Pixel 6a class per Performance Basics - iPhone Pro lies.
Use error budgets to gate releases: Burn > 50% in a week → feature freeze; 0% → halt store and OTA per Rollback Runbook.
Run observability review before major OTAs: Staged rollout + Release Health + OTA success SLO - rollback channel before store emergency.
Stack versions: This page was written for React 19.2.3, React Native 0.86.0, and Expo SDK 57 (
expo~57.0.4).
Reviewed by Chris St. John·Last updated Jul 19, 2026