Mobile RUM - React Native SDK
The React Native SDK helps you analyse real user experience across iOS and Android from a single JavaScript codebase. It automatically tracks sessions, instruments HTTP calls, propagates trace context to your backend, captures JS errors, observes navigation changes, and records native crashes. Use the guides below to install, initialise, and tune the SDK with privacy‑first defaults.
Prerequisites#
Use React Native 0.68+. Confirm your version:
1npx npm view react-native versionAs of SDK 2.0.0, the React Native package wraps the stable native Middleware SDKs (Android 3.x, iOS 2.1+), which adds these host-app requirements:
- Android:
compileSdk35+, Kotlin (KGP) 2.0+, and core library desugaring enabled. - iOS: minimum deployment target 13.0. The
MiddlewareRumpod is a static framework — underuse_frameworks!, dependent pods must also link statically.
Note: Make sure your APIs and the Middleware target use HTTPS. iOS App Transport Security (ATS) and Android cleartext policies can block HTTP in production builds.
Install & Instrument Your React Application#
1 Install Middleware React Native SDK#
Add the SDK to your project. This brings in the runtime, native modules, and TS types. The latest release is 2.1.4. For production, pin a version. For quick starts, the latest is fine.
1yarn add @middleware.io/middleware-react-native
2 cd ios && pod install2 Initialize the Middleware React Native SDK#
Initialise the SDK before your app renders so it can observe startup, navigation, and early network calls. The configuration identifies your app (serviceName, projectName), sets your ingest target, and adds stable release tags. Keep PII out of attributes and prefer IDs.
1import React from 'react';
2import { MiddlewareWrapper, type ReactNativeConfiguration } from '@middleware.io/middleware-react-native';
3import App from './App';
4
5const MiddlewareConfig: ReactNativeConfiguration = {
6 serviceName: 'Mobile-SDK-ReactNative',
7 projectName: 'Mobile-SDK-ReactNative',
8 accountKey: '<MW_API_KEY>',
9 target: '<target-url>',
10 deploymentEnvironment: 'PROD',
11 // Optional: default attributes used for filtering and release correlation
12 globalAttributes: {
13 username: '<your-name>',
14 'app.version': '1.0.0',
15 },
16 // sessionRecording: true // default; see Session Recordings
17};
18
19export default function Root() {
20 return (
21 <MiddlewareWrapper config={MiddlewareConfig}>
22 <App />
23 </MiddlewareWrapper>
24 );
25}Navigation: The SDK auto‑tracks route changes in standard React Navigation setups. Keep your NavigationContainer at the top level so route transitions are visible to the wrapper.
Consent (optional): If you gate analytics on user consent, render the MiddlewareWrapper only after consent, or set sessionRecording: false until consent is granted.
Custom Configurations#
Configuration reference#
Every field of ReactNativeConfiguration. Only the first four are required.
| Option | Type | Default | Description |
|---|---|---|---|
target | string | — | Ingest URL telemetry is sent to |
accountKey | string | — | Authorizes the client to send telemetry to Middleware |
serviceName | string | — | Service name for your application |
projectName | string | — | Project name your app reports under |
deploymentEnvironment | string | — | Environment attribute on generated spans, e.g. PROD, DEV |
globalAttributes | Attributes | {} | Attributes added to every span. See Global Attributes |
appStartEnabled | boolean | true | Records the app‑start span |
debug | boolean | false | Verbose SDK logging via the OpenTelemetry diagnostic logger |
sessionRecording | boolean | true | Enables session replay. See Session Recordings |
recordingOptions | object | see below | Capture frequency, quality, and masking |
disableSessionRecordingV3 | boolean | false | Falls back to the legacy (v2) screenshot recorder |
sessionSamplingRatio | number | 1.0 | Fraction of sessions kept for traces and recordings, 0.0–1.0 |
networkInstrumentation | boolean | true | Set false to disable fetch/XHR instrumentation |
tracePropagationTargets | Array<string | RegExp> | every URL | Which requests carry trace headers. See Distributed Tracing |
tracePropagationFormat | 'w3c' | 'b3' | both | Restricts the header format sent |
ignoreUrls | Array<string | RegExp> | Middleware ingest endpoints | Additional URLs that are not traced. The SDK's own /v1/* calls are always excluded |
ignoreHeaders | Set<string> | ∅ | Headers dropped from captured events. Separately, x-access-token is always masked and cannot be un-masked |
enableDiskBuffering, limitDiskUsageMegabytes, truncationCheckpoint, bufferTimeout, and bufferSize are accepted by the type but were never wired to the native SDKs. They are deprecated and slated for removal — setting them has no effect.
Network Instrumentations#
Network instrumentation captures request method, URL, response status, content length, and select headers by default. Use the following options to scope or redact what’s collected.
Ignore specific URLs — pass Array<string | RegExp> in ignoreUrls:
1const MiddlewareConfig: ReactNativeConfiguration = {
2 // ...
3 ignoreUrls: [/^\/api\/facts/, /^\/api\/v1\/users\/.*/],
4};Captured content types (default): application/json, application/text, text/x-component.
Redact headers: pass a Set<string> in ignoreHeaders:
1const MiddlewareConfig: ReactNativeConfiguration = {
2 // ...
3 ignoreHeaders: new Set(['x-ignored-header']),
4};ignoreHeaders is empty by default. Separately and regardless of it, the value of x-access-token is always replaced with ******** — the header is still recorded, but its value never leaves the device.
Disable network instrumentation (if needed):
1const MiddlewareConfig: ReactNativeConfiguration = {
2 // ...
3 networkInstrumentation: false,
4};Tip: If some calls aren’t appearing, check whether they’re performed by libraries that bypass the global fetch/XHR stack, or whether they match an ignoreUrls rule.
Distributed Tracing#
End‑to‑end tracing links a RUM session to the backend traces it caused, so you can open a slow screen in the Session Explorer and see the server spans behind it.
It works by trace‑context propagation: the SDK creates a client span for each outgoing request and injects the W3C traceparent header. Your instrumented backend continues that same trace, and Middleware correlates the two by trace ID. For the full picture across RUM, traces, and logs, see Correlation with Data.
This is on by default and requires no code. Every request made through fetch or XMLHttpRequest is traced and carries trace headers. Requests to the Middleware ingest endpoints are excluded.
The only remaining requirement is that your backend services are instrumented and accept W3C Trace Context.
Restricting which hosts receive trace headers#
To keep your trace IDs off third‑party APIs, narrow propagation to your own domains with tracePropagationTargets, which takes Array<string | RegExp>:
1const MiddlewareConfig: ReactNativeConfiguration = {
2 // ...
3 tracePropagationTargets: [/api\.example\.com/, /checkout\.example\.com/],
4};Requests to other hosts are still timed and still appear in the session — they just travel without trace headers. An explicit empty array disables propagation entirely.
Prefer regexes. A RegExp entry is matched against the URL, but a plain string entry has to equal the whole URL exactly — so 'api.example.com' matches nothing.
By default both W3C (traceparent) and B3 headers are sent. Narrow this with tracePropagationFormat:
1const MiddlewareConfig: ReactNativeConfiguration = {
2 // ...
3 tracePropagationFormat: 'w3c', // or 'b3'
4};Verifying it works#
In the Session Explorer, open a network event and check that the backend trace resolves.
- Backend spans appear — correlation is working end to end.
- A trace ID is present but no backend spans — the request propagated correctly and the gap is server‑side; confirm that service is instrumented and accepts W3C Trace Context.
- No trace at all — if you set
tracePropagationTargets, confirm it actually matches the URL being called.
Logs#
Client logs are lightweight signals correlated with sessions and replays. Use levels to reflect severity; avoid secrets.
1MiddlewareRum.debug('I am debug');
2MiddlewareRum.error('I am error');
3MiddlewareRum.info('I am info');
4MiddlewareRum.warn('I am warn');Global Attributes#
Attach stable keys you’ll filter and chart by (release, tenant, plan). You can set them at init (globalAttributes) and update later with setGlobalAttributes.
1MiddlewareRum.setGlobalAttributes({
2 username: 'Middleware',
3 custom_key: 'some value',
4});Custom Errors#
Crashes are captured automatically. Use reportError for handled exceptions that you still want on the dashboard and tied to the session/replay.
1try {
2 throw new Error('I am error');
3} catch (err) {
4 MiddlewareRum.reportError(err as Error);
5}Updating Location Information#
If your experience depends on user location, you can enrich sessions with latitude and longitude. Only collect what you need for business logic.
1MiddlewareRum.updateLocation(latitude: number, longitude: number);Session Recordings#
Replay helps you see what users saw, which is ideal for diagnosing regressions and validating fixes. As of SDK 2.0.0, recording uses the native SDKs' next-generation pipeline (rrweb-based): it starts automatically, captures the real native screen (including embedded platform views), and plays back frame-accurately in the Middleware session player. JS-level context — screen names from React Navigation, session boundaries, custom events — is linked into the same session automatically.
- Max duration: 4 hours per session
- Idle timeout: 15 minutes of inactivity ends a recording; activity creates a new session
- Default: Recording is enabled; disable with
sessionRecording: false
Tune capture rate, quality, and masking with recordingOptions:
1const MiddlewareConfig: ReactNativeConfiguration = {
2 // ...
3 recordingOptions: {
4 frequency: 'standard', // 'low' | 'standard' | 'high'
5 quality: 'standard', // 'low' | 'standard' | 'high'
6 maskAllTextInputs: true, // default: true
7 maskAllImages: true, // default: true
8 },
9 // sessionSamplingRatio: 1.0, // record a fraction of sessions
10};Disable recording example:
1const MiddlewareConfig: ReactNativeConfiguration = {
2 serviceName: 'Mobile-SDK-ReactNative',
3 projectName: 'Mobile-SDK-ReactNative',
4 accountKey: 'your-account-token',
5 target: '<target-url>',
6 sessionRecording: false,
7 deploymentEnvironment: 'PROD',
8 globalAttributes: {
9 name: '<your-name>',
10 'app.version': '1.0.0',
11 },
12};Privacy#
Masking happens on device before upload. Wrap any component tree that may contain sensitive content (payments, OTPs, tokens) so it’s blurred in all recordings.
1<MiddlewareSanitizedView>
2 <Component />
3</MiddlewareSanitizedView>Password fields are masked automatically by default. Review high‑risk screens regularly and expand masking as needed.
Platform Notes (iOS & Android)#
- HTTPS required: iOS ATS blocks non‑TLS by default; Android blocks cleartext HTTP on API 28+ unless explicitly allowed. Use HTTPS for APIs and your Middleware target.
- App start coverage: Initialise in your app entry point and keep the wrapper at the top of the tree for complete navigation visibility.
- Performance: Sanitising large trees is safe but may add overhead; prefer wrapping only the regions that actually contain sensitive content.
Troubleshooting#
Start here if data isn’t appearing or specific signals are missing.
- No data at all: Verify
accountKeyandtarget, ensure the wrapper renders once at app start, and check device connectivity. - No network events: Confirm
networkInstrumentationis enabled and requests aren’t excluded byignoreUrls. Some low‑level clients may bypass the global stack. - Nothing in Session Replay: Ensure
sessionRecordingisn’t set to false, and that the app stayed active (idle timeout is 15 minutes). - Privacy not applied: Make sure sensitive components are actually wrapped in
MiddlewareSanitizedView. - Navigation not tracked: Keep
NavigationContainerunder theMiddlewareWrapperand avoid memory‑only routers in production. - No backend traces linked to a session: Almost always an empty or non-matching
tracePropagationTargets— the SDK logs a warning at startup when none are set. See Distributed Tracing. - Trace headers reaching a third-party API: Narrow
tracePropagationTargetsto your own domains.
Need assistance or want to learn more about Middleware? Get in touch with us via our Contact Us or join our Slack channel.