SpitfireLoad Testing & Observabilityv1.1.0 · What's new

Version: 1.1.0This documentation is for Spitfire 1.1.0.

Connecting a React Native app with OTel

React Native and Expo: fetch/XHR calls as traces, linked to your backend with traceparent. Values: Connecting services with OTel: overview.

Version table

React Native Metro Expo Packages
0.79 and later as shipped SDK 53 and later the React.js versions, without document-load, user-interaction, context-zone, zone.js
0.76 – 0.78 0.81.3 or later SDK 52 the same
0.75 and earlier – – not supported; upgrade to 0.79

Find your version: npx react-native --version (Expo: npx expo --version)

Traces only. OTel marks browser and React Native instrumentation as experimental. Device runs were not part of our check; the code was type-checked against these packages.

Verified: 2026-11-04. Source: OTel JS 3.0.0 README, React Native support, OTel JS 3.x migration guide, npm @opentelemetry/sdk-trace, npm @opentelemetry/exporter-trace-otlp-http.

What you need

  • Spitfire address https://<spitfire> (HTTPS: Android and iOS refuse plain HTTP)
  • Service name <service-name>, version <service-version>, environment <environment>
  • The app folder (here /srv/app, where package.json is)
  • Your API address, as a regular expression (here ^https://api\.example\.com/)

React Native and Expo

  1. Create the key: Observability → Browser and app key, leave Allowed origins empty; copy sfrum_… (Observability).

  2. Add the packages:

bash
cd /srv/app && npm i @opentelemetry/api@1.10.0 @opentelemetry/sdk-trace@3.0.0 @opentelemetry/core@3.0.0 @opentelemetry/resources@3.0.0 @opentelemetry/exporter-trace-otlp-http@0.300.0 @opentelemetry/instrumentation@0.300.0 @opentelemetry/instrumentation-fetch@0.300.0 @opentelemetry/instrumentation-xml-http-request@0.300.0
  1. Create /srv/app/otel.ts and paste:
ts
// IS_OTEL_ENABLED=true: OTel on; any other value: off.
import { context, propagation, trace } from '@opentelemetry/api';
import { CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator } from '@opentelemetry/core';
import { resourceFromAttributes } from '@opentelemetry/resources';
import { BatchSpanProcessor, ParentBasedSampler, StackContextManager, TraceIdRatioBasedSampler, TracerProvider } from '@opentelemetry/sdk-trace';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch';
import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request';

const IS_OTEL_ENABLED: string = 'true';
const OTEL_SERVICE_NAME = '<service-name>';
const OTEL_SERVICE_VERSION = '<service-version>';
const OTEL_ENVIRONMENT = '<environment>';
const OTEL_TRACES_ENDPOINT = 'https://<spitfire>/otlp/v1/traces';
const OTEL_KEY = 'sfrum_…';
const OTEL_TRACES_SAMPLER_ARG = 0.1;
const OTEL_PROPAGATE_URLS = /^https:\/\/api\.example\.com\//;

if (IS_OTEL_ENABLED === 'true') {
  const provider = new TracerProvider({
    resource: resourceFromAttributes({
      'service.name': OTEL_SERVICE_NAME,
      'service.version': OTEL_SERVICE_VERSION,
      'deployment.environment': OTEL_ENVIRONMENT,
    }),
    sampler: new ParentBasedSampler({ root: new TraceIdRatioBasedSampler(OTEL_TRACES_SAMPLER_ARG) }),
    spanProcessors: [new BatchSpanProcessor({
      exporter: new OTLPTraceExporter({ url: OTEL_TRACES_ENDPOINT, headers: { Authorization: `Bearer ${OTEL_KEY}` } }),
    })],
  });
  trace.setGlobalTracerProvider(provider);
  context.setGlobalContextManager(new StackContextManager().enable());
  propagation.setGlobalPropagator(new CompositePropagator({ propagators: [new W3CTraceContextPropagator(), new W3CBaggagePropagator()] }));
  registerInstrumentations({
    instrumentations: [
      new FetchInstrumentation({ propagateTraceHeaderCorsUrls: [OTEL_PROPAGATE_URLS] }),
      new XMLHttpRequestInstrumentation({ propagateTraceHeaderCorsUrls: [OTEL_PROPAGATE_URLS] }),
    ],
  });
}
  1. Make it the first line of /srv/app/index.js (Expo Router: create /srv/app/index.js with it and import 'expo-router/entry';, and set "main": "index.js" in package.json):
ts
import './otel';
  1. Build the release (Android; iOS: --mode Release with run-ios):
bash
cd /srv/app && npx react-native run-android --mode release
  1. Expo: build the release instead:
bash
cd /srv/app && npx expo run:android --variant release

Verify

  1. Spitfire takes the key from an app (no Origin):
bash
curl -s -o /dev/null -w '%{http_code}' -X POST https://<spitfire>/otlp/v1/traces -H 'Authorization: Bearer sfrum_…' -H 'Content-Type: application/json' -d '{}' | grep -q '^200
  

 && echo OK
  1. The app loads the file first:
bash
head -n 1 /srv/app/index.js | grep -q "import './otel'" && grep -q "IS_OTEL_ENABLED: string = 'true'" /srv/app/otel.ts && echo OK

Turning off and removing

  1. Turn off: in otel.ts write const IS_OTEL_ENABLED: string = 'false';, then build again.
  2. Remove:
bash
cd /srv/app && npm uninstall @opentelemetry/api @opentelemetry/sdk-trace @opentelemetry/core @opentelemetry/resources @opentelemetry/exporter-trace-otlp-http @opentelemetry/instrumentation @opentelemetry/instrumentation-fetch @opentelemetry/instrumentation-xml-http-request && rm -f otel.ts && sed -i.bak "/import '.\/otel';/d" index.js

Common problems

Symptom Fix
Metro: Unable to resolve an @opentelemetry file React Native 0.79, or Metro 0.81.3 or later
401 The key is sfrum_…, enabled, after Bearer
403 origin not allowed Web build (Expo web): add its address to Allowed origins
429 Raise the key's Exports per minute or lower OTEL_TRACES_SAMPLER_ARG
App and backend spans are not one trace OTEL_PROPAGATE_URLS must match your API address
No spans from the device The phone must reach https://<spitfire>