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, wherepackage.jsonis) - Your API address, as a regular expression (here
^https://api\.example\.com/)
React Native and Expo
Create the key: Observability → Browser and app key, leave Allowed origins empty; copy
sfrum_…(Observability).Add the packages:
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- Create
/srv/app/otel.tsand paste:
// 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] }),
],
});
}- Make it the first line of
/srv/app/index.js(Expo Router: create/srv/app/index.jswith it andimport 'expo-router/entry';, and set"main": "index.js"inpackage.json):
import './otel';- Build the release (Android; iOS:
--mode Releasewithrun-ios):
cd /srv/app && npx react-native run-android --mode release- Expo: build the release instead:
cd /srv/app && npx expo run:android --variant releaseVerify
- Spitfire takes the key from an app (no
Origin):
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