React Native + Expo SDK
The official Pionne SDK for React Native and Expo. Auto-captures JS errors, native iOS/Android errors, and Hermes errors. Works with Expo managed and bare workflow.
Current version: 0.8.6
Install
Section titled “Install”npm install @pionne/react-nativeBasic init
Section titled “Basic init”import { Pionne } from '@pionne/react-native';
Pionne.init({ token: 'pio_live_…' });Skip the SDK in dev
Section titled “Skip the SDK in dev”To stop polluting your prod dashboard with debug events from Metro / Expo Go (and dodge the bundle ID mismatch headache between Expo Go’s host.exp.Exponent and the bundle pinned on your project), pass enableInDev: false:
Pionne.init({ token: 'pio_live_…', enableInDev: false, // no-op in __DEV__});In __DEV__, init() logs [Pionne] Skipped in __DEV__ (enableInDev=false) and every method (captureException, captureMessage, setUser, etc.) is a silent no-op for the lifetime of the process. No global handlers installed, no session opened. Default behavior: enableInDev: true (backward compat).
Native crash capture
Section titled “Native crash capture”JS handlers (ErrorUtils, the promise tracker, the Error Boundary) can only see crashes on the JS thread. A native crash tears down the whole process, JS VM included, before any JS can run. So Pionne leans on the OS to record them and replays them as fatal events on the next launch.
On by default. To disable:
Pionne.init({ token: 'pio_live_…', captureNativeCrashes: false,});What’s captured on iOS 14+
Section titled “What’s captured on iOS 14+”Via MetricKit (MXCrashDiagnostic):
- Objective-C / Swift
NSException— exception name + composed message on iOS 17+ (e.g.NSInvalidArgumentException) - Signals —
SIGSEGV,SIGABRT,SIGBUS,SIGILL,SIGFPE,SIGTRAP - Out-of-memory kills and watchdog terminations (
0x8badf00d) - Call stack tree — system frames symbolicated by the OS; app frames as
binaryName 0xADDRESS(no dSYM symbolication step)
What’s captured on Android 11+
Section titled “What’s captured on Android 11+”Via ActivityManager.getHistoricalProcessExitReasons():
REASON_CRASH— unhandled JVM exceptionREASON_CRASH_NATIVE— NDK / native (C/C++) crashREASON_ANR— Application Not Responding (with the ANR trace)REASON_LOW_MEMORY— OOM kill
Native crashes arrive on the launch after the crash (the OS delivers them post-mortem), with mechanism.type = "native" and a native.source tag (metrickit on iOS, app_exit on Android).
iOS 26 + new architecture stability fix
Section titled “iOS 26 + new architecture stability fix”On the very narrow surface of iOS 26 + new architecture in production, React Native re-throws JS errors through a void TurboModule on an async dispatch queue, which the runtime aborts as an unrecoverable SIGABRT (RN #54859). Since 0.9.1, the SDK detects that exact combination and suppresses the re-throw after capturing the event — the host app keeps running. Every other runtime (older iOS, Android, old architecture, dev mode) keeps the default React Native behaviour.
Detailed documentation
Section titled “Detailed documentation”This page is an alias for the React Native SDK’s main documentation. The full guides:
- Quickstart — integrate Pionne in 5 minutes
- Installation — advanced setup, Expo vs bare
- SDK API — full method reference
- Auto-capture — what’s captured with zero config
- Breadcrumbs — action trail leading to the crash
- Error Boundary — React capture component
- Screenshots — visual capture at crash time
- PII — personal data scrubbing
- Source maps — Hermes stack symbolication
Geography (opt-in)
Section titled “Geography (opt-in)”Pionne can attach the user’s approximate city/region/country to each event. Off by default for privacy:
Pionne.init({ token: 'pio_live_…', sendGeography: true, // ← opt-in});At boot, a single HTTP call to https://ipapi.co/json/ (4 s timeout) resolves contexts.geo = { city, region, country, country_code } and attaches it to every subsequent event. No iOS/Android permission required (no GPS, just IP reverse-lookup). If the lookup fails, the SDK keeps working without geo.
You can swap the provider via geographyEndpoint: '…' — any URL returning JSON { city, region, country, country_code } works.
Anti-token-theft
Section titled “Anti-token-theft”The bundle ID (com.yourapp.app) is auto-pinned server-side on the first event received. If someone steals your token and tries to use it from another app, those events get rejected automatically.
See also
Section titled “See also”- Web SDK — pure browser apps
- Node.js SDK — Node backends
- Ingest API — raw HTTP protocol