npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@middleware.io/middleware-react-native

v2.3.2

Published

Middleware React Native real user monitoring SDK

Downloads

744

Readme

Middleware React Native SDK

Middleware React Native Real User Monitoring SDK



Features

  • AutoInstrumentation HTTP Monitoring
  • AutoInstrumentaion JS Errors
  • AutoInstrumenation navigation tracking for react-navigation
  • AutoInstrumenation native crash errors
  • Custom Instrumenation using OpenTelemetry
  • Custom logging
  • RUM Session Tracking
  • Session Recording

Documentation

Compatibility & Requirements

Middleware React Native for Mobile supports React Native 0.68 and higher.

Since v2.0.0 the SDK wraps the stable Middleware native SDKs (io.github.middleware-labs:android-sdk 3.1.4+ and the MiddlewareRum CocoaPod 2.2.3+), which brings v3 session recording (rrweb replay), native crash/ANR reporting, and screen-name linked replays. Native toolchain requirements:

  • Android: compileSdkVersion 35+, Kotlin Gradle Plugin 2.0.21+ (pin classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.21") on React Native < 0.77), minSdkVersion 21. If your app still enables Jetifier, add android.jetifier.ignorelist=jackson-core to gradle.properties.

  • iOS: deployment target 13.0+, CocoaPods (the MiddlewareRum pod is pulled automatically). When building pods as static libraries (the default), add pod 'Reachability', :modular_headers => true to your Podfile. Also add these sources to the top of ios/Podfile:

    source 'https://github.com/middleware-labs/cocoapods-specs.git'
    source 'https://cdn.cocoapods.org/'

    CocoaPods trunk stops accepting new pods on December 2, 2026, so new MiddlewareRum versions are published to the Middleware repo. Without that source, your app stays on the last version published to trunk.

The library is also compatible with the following frameworks and libraries:

  • Expo (SDK 52+, via a development build — see below)
  • React Navigation 5, 6 and 7

Installation

yarn add @middleware.io/middleware-react-native

Expo

This SDK contains custom native code, so it cannot run in Expo Go — Expo Go ships a fixed native binary and has no way to load the Middleware native SDKs. You need a development build.

Add the config plugin to app.json / app.config.js:

{
  "expo": {
    "plugins": ["@middleware.io/middleware-react-native"]
  }
}

Then create a development build:

npx expo prebuild --clean     # regenerate ios/ and android/ with the plugin applied
npx expo run:android          # or: npx expo run:ios

For EAS, eas build --profile development picks the plugin up automatically.

The plugin applies the native requirements that a managed project can't set on its own:

| Change | Why | | --- | --- | | android.jetifier.ignorelist=jackson-core | Jetifier fails on the jackson-core inside android-sdk 3.x | | Kotlin Gradle Plugin >= 2.0.21 | android-sdk 3.x is compiled with Kotlin 2.0.21 metadata | | compileSdkVersion >= 35 | required by android-sdk 3.x (an already-higher value is left alone) | | iOS deployment target >= 13.0 | minimum for the MiddlewareRum pod | | pod 'Reachability', :modular_headers => true | Reachability ships no modulemap, so Swift can't import it under static libraries (skipped when the app uses use_frameworks!) |

Options, if you need to override a default:

{
  "expo": {
    "plugins": [
      ["@middleware.io/middleware-react-native", {
        "kotlinVersion": "2.0.21",
        "compileSdkVersion": 35,
        "iosDeploymentTarget": "13.0",
        "jetifierIgnorelist": true,
        "reachabilityModularHeaders": true
      }]
    ]
  }
}

Checking that the native SDK is actually linked

If spans stop flowing, the first thing to check is whether the native module made it into the binary:

import { MiddlewareRum } from '@middleware.io/middleware-react-native';

console.log('Middleware native linked:', MiddlewareRum.isNativeAvailable());

false means you are on Expo Go, or running a binary built before the package was added — rebuild with npx expo run:android / run:ios.

The SDK falls back to sending traces from JS over OTLP/HTTP in two cases: the native module isn't linked, or native initialization failed. Either way traces still reach Middleware, while crash/ANR reporting and session recording stay off until the native side is healthy. Native failures are logged with their cause, for example:

ERROR [MiddlewareRum] native initialize failed: Method addObserver must be called on the main thread

Set debug: true in your configuration to also see per-export detail.

Usage

import { MiddlewareWrapper, type ReactNativeConfiguration } from '@middleware.io/middleware-react-native';
        
const MiddlewareConfig: ReactNativeConfiguration = {
    serviceName: 'Mobile-SDK-ReactNative',
    projectName: '$Mobile-SDK-ReactNative',
    accountKey: '<middleware-account-key>',
    target: '<target-url>',
    deploymentEnvironment: 'PROD',
    globalAttributes: {
        name: '<your-name>',
    },
};

export default function App() { 
    return (
      <MiddlewareWrapper configuration={MiddlewareConfig}>
        // Application Components
      </MiddlewareWrapper>
    );
  }

Custom logging

You can add custom logs such as debug, error, warn, info these logs will be shown on Middleware Logs Dashboard

MiddlewareRum.debug("I am debug");
MiddlewareRum.error("I am error");
MiddlewareRum.info("I am info");
MiddlewareRum.warn("I am warn");

Setting Global Attributes

You can set global attributes by calling setGlobalAttributes function.

MiddlewareRum.setGlobalAttributes({
    "name": "Middleware",
    "app.version": "1.0.0",
    "custom_key": "some value"
});

Network instrumentation

To ignore capturing urls pass Array<String | RegExp> in ignoreUrls key in ReactNativeConfiguration

Example:

  ignoreUrls: [/^\/api\/facts/, /^\/api\/v1\/users\/.*/],

Capturing headers and response bodies

Network spans carry the method, URL, status and timings. Headers and response bodies are not captured by default — turn them on separately:

| Option | Default | Captures | | --- | --- | --- | | captureNetworkHeaders | false | Request and response headers, as http.request.header.<name> / http.response.header.<name> (lowercase, - → _). Also links the span to your backend trace from a Server-Timing: traceparent;desc="…" response header. | | captureResponseBodies | false | Response bodies, as http.response.body, only when the Content-Type is application/json, *+json (e.g. application/problem+json) or text/plain. Truncated to 64 KiB. |

const MiddlewareConfig: ReactNativeConfiguration = {
    ...
    captureNetworkHeaders: true,
    captureResponseBodies: true,
};

Request bodies are never captured.

This package depends on Android android-sdk 3.2.2+ and iOS MiddlewareRum 2.3.0+. React Native's requests are traced by the JS instrumentation only: native URLSession tracing is turned off on iOS, so each request produces one span. As a result, requests made directly by native code (native modules, third-party native SDKs, images loaded by <Image>) are not traced on iOS. On Android the settings are passed to the native SDK, where they apply to HTTP traced through its OkHttp call factory.

Changed in 2.3.0: earlier versions recorded request headers, response headers, request bodies and response bodies on every request. Set the options above to keep capturing headers or response bodies.

To leave specific headers out, list them in ignoreHeaders (case-insensitive; a Set or an array):

ignoreHeaders: new Set(['Authorization', 'x-ignored-header']),

Note: x-access-token is always masked.

To disable network instrumentation set networkInstrumentation: false

const MiddlewareConfig: ReactNativeConfiguration = {
    ...
    networkInstrumentation: false
};

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.

This is on by default and requires no code. Every request made through fetch or XMLHttpRequest is traced and carries trace headers.

To keep your trace IDs off third-party APIs, narrow propagation to your own domains with tracePropagationTargets, which takes Array<string | RegExp>:

const MiddlewareConfig: ReactNativeConfiguration = {
    ...
    tracePropagationTargets: [/api.example.com/, /anotherapi.example.com/]
};

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. Use tracePropagationFormat: 'w3c' or 'b3' to send only one.

Reporting custom errors

You can report handled errors, exceptions, and messages using the reportError function

try{
    throw new Error("I am error")
} catch (err) {
    MiddlewareRum.reportError(err);
}

Updating location information

You can set latitude & longitde as global attributes.

MiddlewareRum.updateLocation(latitude: number, longitude: number)

Enable session recording

By default session recording is enabled, to disable session recording pass sessionRecording: false configuration as follows -

const MiddlewareConfig: ReactNativeConfiguration = {
    serviceName: 'Mobile-SDK-ReactNative',
    projectName: '$Mobile-SDK-ReactNative',
    accountKey: '<middleware-account-key>',
    target: '<target-url>',
    sessionRecording: false,
    deploymentEnvironment: 'PROD',
    globalAttributes: {
        name: '<your-name>',
    },
};

Recording options

Tune how the recording is captured with recordingOptions:

const MiddlewareConfig: ReactNativeConfiguration = {
    // ...
    sessionRecording: true,
    recordingOptions: {
        frequency: 'standard',   // 'low' (~1 fps, default) | 'standard' | 'high'
        quality: 'standard',     // 'low' | 'standard' (default) | 'high'
        maskAllTextInputs: true, // default false (masks all text and WebViews)
        maskAllImages: true,     // default false (masks images and WebViews)
    },
    // Fraction of sessions that get recorded (0.0 - 1.0). Defaults to 1.0.
    sessionSamplingRatio: 1.0,
};

Starting and stopping recording at runtime

Recording can be controlled after initialization — useful when you only want to record a specific flow:

import { MiddlewareRum } from '@middleware.io/middleware-react-native';

await MiddlewareRum.startRecording(); // -> boolean: recording is running
await MiddlewareRum.stopRecording();  // -> boolean: recording was stopped
await MiddlewareRum.isRecording();    // -> boolean

Both calls are sticky: they survive session rotation and override the session sampler, so recording stays in the state you asked for until you change it again.

startRecording() also overrides sessionRecording: false, which lets you keep recording off by default and turn it on only where you need it:

MiddlewareRum.init({ ...config, sessionRecording: false });

// later, e.g. when the user enters the checkout flow
await MiddlewareRum.startRecording();
// ...
await MiddlewareRum.stopRecording();

Sanitizing views in session recording

Views will get blurred hiding sensitive information in session recording.

<MiddlewareSanitizedView>
  <Component/>
</MiddlewareSanitizedView>

Slow rendering detection

The native SDK reports slowRenders and frozenRenders spans. To turn them off, pass slowRenderingDetection: false. Relaunch the app for the change to apply, because a JS reload keeps the native settings.

const MiddlewareConfig: ReactNativeConfiguration = {
    // ...
    slowRenderingDetection: false,
};

Contributing

See the contributing guide to learn how to contribute to the repository and the development workflow.

License

Apache 2.0