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 version

As 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: compileSdk 35+, Kotlin (KGP) 2.0+, and core library desugaring enabled.
  • iOS: minimum deployment target 13.0. The MiddlewareRum pod is a static framework — under use_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 install

2 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.

OptionTypeDefaultDescription
targetstringIngest URL telemetry is sent to
accountKeystringAuthorizes the client to send telemetry to Middleware
serviceNamestringService name for your application
projectNamestringProject name your app reports under
deploymentEnvironmentstringEnvironment attribute on generated spans, e.g. PROD, DEV
globalAttributesAttributes{}Attributes added to every span. See Global Attributes
appStartEnabledbooleantrueRecords the app‑start span
debugbooleanfalseVerbose SDK logging via the OpenTelemetry diagnostic logger
sessionRecordingbooleantrueEnables session replay. See Session Recordings
recordingOptionsobjectsee belowCapture frequency, quality, and masking
disableSessionRecordingV3booleanfalseFalls back to the legacy (v2) screenshot recorder
sessionSamplingRationumber1.0Fraction of sessions kept for traces and recordings, 0.01.0
networkInstrumentationbooleantrueSet false to disable fetch/XHR instrumentation
tracePropagationTargetsArray<string | RegExp>every URLWhich requests carry trace headers. See Distributed Tracing
tracePropagationFormat'w3c' | 'b3'bothRestricts the header format sent
ignoreUrlsArray<string | RegExp>Middleware ingest endpointsAdditional URLs that are not traced. The SDK's own /v1/* calls are always excluded
ignoreHeadersSet<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 accountKey and target, ensure the wrapper renders once at app start, and check device connectivity.
  • No network events: Confirm networkInstrumentation is enabled and requests aren’t excluded by ignoreUrls. Some low‑level clients may bypass the global stack.
  • Nothing in Session Replay: Ensure sessionRecording isn’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 NavigationContainer under the MiddlewareWrapper and 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 tracePropagationTargets to 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.