React Native RUM SDK
Install and configure the Last9 React Native RUM SDK. TypeScript API, CDN-hosted npm tarball, bridges native Android and iOS SDKs. Auto-instruments fetch/XHR, React Navigation, errors, ANRs.
Real User Monitoring for React Native apps. Automatic instrumentation for sessions, views, network requests (fetch/XHR), errors, and resource metrics via OpenTelemetry. ANR detection is available on Android only.
The React Native SDK wraps the Android and iOS native SDKs. Each platform’s CDN repo must be configured so the native dependencies resolve.
Prerequisites
- React Native >= 0.74
- iOS 15.1+
- Android minSdk 21 (Android 5.0+)
- Native dependencies:
- Android:
io.last9:rum-android:0.7.0(resolved from CDN Maven) - iOS:
Last9RUM 0.7.0(resolved from CDN podspec)
- Android:
CDN artifacts
| Artifact | URL |
|---|---|
| Tarball | https://cdn.last9.io/rum-sdk/react-native/builds/0.7.0/last9-rum-react-native-0.7.0.tgz |
| Checksum | https://cdn.last9.io/rum-sdk/react-native/builds/0.7.0/last9-rum-react-native-0.7.0.tgz.sha256 |
Staging builds use the -alpha.<run_number> suffix.
Installation
-
Install the package
npm install https://cdn.last9.io/rum-sdk/react-native/builds/0.7.0/last9-rum-react-native-0.7.0.tgz -
Android — add the CDN Maven repository
In
android/settings.gradle(orandroid/build.gradle):dependencyResolutionManagement {repositories {google()mavenCentral()maven { url = uri("https://cdn.last9.io/rum-sdk/android/maven/") }}} -
iOS — add the Last9RUM podspec
In
ios/Podfile:pod 'Last9RUM', :podspec => 'https://cdn.last9.io/rum-sdk/ios/builds/0.7.0/Last9RUM.podspec'Then install pods:
cd ios && pod install -
Initialize the SDK
At app entry (before any screens render):
import { L9Rum } from "@last9/rum-react-native";L9Rum.initialize({baseUrl: "https://otlp-ext-aps1.last9.io/v1/otlp/organizations/<org>",origin: "https://app.last9.io",clientToken: "your-client-token",serviceName: "my-rn-app",serviceVersion: "1.0.0",deploymentEnvironment: "production",});
Configuration
L9Rum.initialize({ // --- Required ---------------------------------------------------------
// OTLP collector endpoint baseUrl: "https://otlp-ext-aps1.last9.io/v1/otlp/organizations/<org>",
// Authentication token from Last9 clientToken: "your-client-token",
// Application identifier (maps to service.name) serviceName: "my-rn-app",
// App version string (maps to service.version) serviceVersion: "1.0.0",
// Environment name deploymentEnvironment: "production",
// --- Optional ---------------------------------------------------------
// Origin sent as X-LAST9-ORIGIN header. // Required for client_monitoring tokens. origin: "https://app.last9.io",
// Specific build identifier (maps to app.build_id) appBuildId: "1.0.0-build-42",
// Unique per-install ID (NOT a hardware ID). Persists across launches. appInstallationId: undefined,
// Session sampling rate: 0-100 (percentage). 100 = sample everything. sampleRate: 100,
// Print debug logs to console debugLogs: false,
// Automatically instrument network requests through native hooks networkInstrumentation: true,
// Automatically capture unhandled JS errors errorInstrumentation: true,
// Max spans per export batch maxExportBatchSize: 100,
// Export timeout in milliseconds exportTimeoutMs: 30000,
// ANR detection (Android only) anrDetectionEnabled: true, anrThresholdMs: 5000,
// Periodically sample memory and CPU resourceMonitoringEnabled: true, resourceSamplingIntervalMs: 30000,
// Setting this to true will hide network requests (and their // DNS/TCP/TLS/TTFB phase child spans) from the Last9 dashboard's // Sessions → APIs tab. Each request would get its own traceId // instead of sharing the current view's traceId, and that tab // only fetches spans that share the View's traceId. Keep this // false unless you specifically need per-request trace isolation. isolateTracePerRequest: false,
// Fine-grained network ignore rules. Strings use substring matching; // RegExp uses regex search semantics. Matched URLs are dropped before // span creation. ignorePatterns: { fullUrl: [ 'https://cdn.example.com', /^https:\/\/.*\.example\.com/i, ], pathname: [ '.pdf', '.jpg', /^\/internal\/metrics/, ], hostname: [ 'cdn.example.com', /(^|\.)assets\.example\.com$/i, ], },
// 'preserve' (default): keep traceparent on ignored requests. // 'strip': remove traceparent from ignored requests. propagationMode: 'preserve',
// Custom resource attributes added to every span resourceAttributes: { "app.platform": "react-native", },
// W3C Baggage propagation on outgoing requests baggage: { enabled: false, allowedKeys: ["session.id", "user.id"], maxTotalBytes: 8192, warnAtPercentage: 80, },});Network ignore patterns
Skip noisy URLs before span creation by matching against full URL, pathname, or hostname. Strings use substring matching; RegExp uses regex search semantics.
L9Rum.initialize({ ignorePatterns: { fullUrl: [ 'https://cdn.example.com', /^https:\/\/.*\.example\.com/i, ], pathname: ['.pdf', '.jpg', /^\/internal\/metrics/], hostname: ['cdn.example.com', /(^|\.)assets\.example\.com$/i], }, // 'preserve' (default): keep traceparent on ignored requests. // 'strip': remove traceparent from ignored requests. propagationMode: 'strip',});Network phase child spans
Network instrumentation is native by default so the SDK emits child spans for individual HTTP phases:
| Child span | What it measures |
|---|---|
dns | DNS lookup duration |
tcp_connect | TCP connection establishment |
tls_handshake | TLS negotiation |
ttfb | Time from request sent to first response byte |
No SDK config change is required. Android wires the OkHttp client factory with the Last9 interceptor and EventListener.Factory. iOS uses native URLProtocol/URLSession instrumentation and reads URLSession task metrics.
Reused connections skip DNS, TCP, and TLS work. For those requests the SDK emits zero-duration child spans with l9rum.network.phase.skipped=true so the waterfall shape stays consistent.
API reference
React Navigation integration
For automatic view tracking with React Navigation:
import { L9ReactNavigationInstrumentation } from '@last9/rum-react-native';import { NavigationContainer } from '@react-navigation/native';
function App() { return ( <NavigationContainer onStateChange={L9ReactNavigationInstrumentation.onStateChange} > {/* screens */} </NavigationContainer> );}Identify a user
L9Rum.identify({ id: "user-123", name: "Jane", email: "jane@example.com", fullName: "Jane Doe", roles: ["admin"],});Clear user on sign-out
L9Rum.clearUser();Capture errors
try { // risky operation} catch (error) { L9Rum.captureError(error, { screen: "checkout" });}Track views manually
L9Rum.startView("ProductDetailsScreen");L9Rum.setViewName("Product #42");Custom events
L9Rum.addEvent("purchase_completed", { product_id: "12345", amount: 29.99,});Global span attributes
L9Rum.spanAttributes({ experiment: "checkout_v2", feature_flag: "new_cart",});
// ClearL9Rum.spanAttributes(null);Session ID
const sessionId = await L9Rum.getSessionId();Flush pending data
L9Rum.flush();WebView correlation
Instrument a react-native-webview WebView to share the native session ID with Browser RUM spans running inside it:
import { useRef } from 'react';import { WebView } from 'react-native-webview';import { L9Rum } from '@last9/rum-react-native';
const webViewRef = useRef<WebView>(null);
<WebView ref={webViewRef} source={{ uri: 'https://app.example.com' }} onLoad={() => { if (webViewRef.current) { L9Rum.instrumentWebView(webViewRef); } }}/>The SDK resolves the underlying native WKWebView (iOS) or android.webkit.WebView (Android) and re-injects session context on every navigation automatically.
See the WebView Session Correlation guide for auto-load options and verification steps.
Next steps
Once data is flowing, explore it in Discover > Applications — performance, errors, and sessions.
Troubleshooting
Please get in touch with us on Discord or Email if you have any questions.