Skip to main content
The Honeycomb OpenTelemetry React Native SDK is Honeycomb’s distribution of OpenTelemetry for React Native applications. It includes instrumentation for things like detecting slow event loops or unhandled exceptions, and provides a component to simplify navigation instrumentation. This page covers basic usage of the SDK. If you just want to see some code, check out the example on GitHub.

Installing the SDK

Before you can use Honeycomb’s OpenTelemetry React Native SDK, you need to install it and configure platform-specific dependencies.
  1. Configure Metro to recognize package.json exports. To do this, create a new file, metro.config.js, in your application’s root directory. Enable package.json exports in your Metro configuration.
    config.resolver.unstable_enablePackageExports = true;
    
    Here’s an example Metro configuration:
    const path = require('path');
    const { getDefaultConfig } = require('@react-native/metro-config');
    const { getConfig } = require('react-native-builder-bob/metro-config');
    const pkg = require('../package.json');
    
    const root = path.resolve(__dirname, '..');
    
    const config = getConfig(getDefaultConfig(__dirname), {
      root,
      pkg,
      project: __dirname,
    });
    
    // Required to use @opentelemetry package.json "exports" field
    config.resolver.unstable_enablePackageExports = true;
    
    module.exports = config;
    
    To learn more about Metro configuration, visit Configuring Metro.
  2. Install Honeycomb’s OpenTelemetry React Native SDK in your application’s root directory using your preferred package manager.
    npm install @honeycombio/opentelemetry-react-native
    
  3. Install the necessary dependencies for each mobile platform your application supports.
    Add the following dependencies to your application’s build.gradle.
    dependencies {
        //...
        implementation "io.honeycomb.android:honeycomb-opentelemetry-android:0.0.20"
        implementation "io.opentelemetry.android:android-agent:0.11.0-alpha"
    }
    
    If your application’s minSDK version is lower than 26, add core library desugaring to your android/app/build.gradle.
    android {
        compileOptions {
            // Enable support for the new language APIs
            coreLibraryDesugaringEnabled true
        }
        dependencies {
            coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.1.5"
        }
    }
    

Initializing

Initialize the SDK at the start of your React Native application. This ensures that events such as startup time and early view loads are captured.
import { HoneycombReactNativeSDK } from '@honeycombio/opentelemetry-react-native';
import { DiagLogLevel } from '@opentelemetry/api';

const sdk = new HoneycombReactNativeSDK({
  // Uncomment the line below to send to EU instance. Defaults to US.
  // endpoint: "https://api.eu1.honeycomb.io:443",
  apiKey: "YOUR-API-KEY",
  serviceName: "YOUR-SERVICE-NAME",
  logLevel: DiagLogLevel.DEBUG,
});

sdk.start();
Initialize the SDK at the start of the onCreate() method in your main Application class.
// MainApplication.kt
override fun onCreate() {
    val options = HoneycombOpentelemetryReactNativeModule.optionsBuilder(this)
        // Uncomment the line below to send to EU instance. Defaults to US.
        // .setApiEndpoint("https://api.eu1.honeycomb.io:443")
        .setApiKey("YOUR-API-KEY")
        .setServiceName("YOUR-SERVICE-NAME")

    HoneycombOpentelemetryReactNativeModule.configure(this, options)
    super.onCreate()
}

Configuring

The Honeycomb React Native SDK can be configured using many of the configuration options from the Honeycomb Web SDK.
import { HoneycombReactNativeSDK } from '@honeycombio/opentelemetry-react-native';
import { DiagLogLevel } from '@opentelemetry/api';
import { ExampleSpanProcessor } from "@/services/ExampleSpanProcessor";

const sdk = new HoneycombReactNativeSDK({
  apiKey: "YOUR-API-KEY",
  // Uncomment the line below to send to EU instance. Defaults to US.
  // endpoint: "https://api.eu1.honeycomb.io:443",
  serviceName: "YOUR-SERVICE-NAME",
  resourceAttributes: {
    "app.environment": "development",
  },
  logLevel: DiagLogLevel.DEBUG,
  
  fetchInstrumentationConfig: {
    propagateTraceHeaderCorsUrls: [
      // Regex to match your backend URLs.
      // Update to the domains you wish to include.
      /.+/g,
    ]
  },

  slowEventLoopInstrumentationConfig: {
    enabled: true,
  },

  spanProcessors: [
    new ExampleSpanProcessor();
  ]
});

sdk.start();

Adding resource attributes

Resource attributes are available on every span your instrumentation emits. Adding custom, application-specific attributes makes it easier to correlate your data to important business information. You can set resource attributes using the resourceAttributes configuration option.
import { HoneycombReactNativeSDK } from '@honeycombio/opentelemetry-react-native';

const sdk = new HoneycombReactNativeSDK({
  apiKey: "YOUR-API-KEY",
  // Uncomment the line below to send to EU instance. Defaults to US.
  // endpoint: "https://api.eu1.honeycomb.io:443",
  serviceName: "YOUR-SERVICE-NAME",
  resourceAttributes: {
    "app.team": "team name",
  },
});

sdk.start();

Enabling sampling

The SDK includes optional deterministic head sampling. The sample rate is 1 by default, meaning every trace is exported. The example below sets a sampleRate of 40, meaning 1 in 40 traces will be exported. This sample rate will only apply to JavaScript/TypeScript traces.
import { HoneycombReactNativeSDK } from '@honeycombio/opentelemetry-react-native';

const sdk = new HoneycombReactNativeSDK({
  apiKey: "YOUR-API-KEY",
  // Uncomment the line below to send to EU instance. Defaults to US.
  // endpoint: "https://api.eu1.honeycomb.io:443",
  serviceName: "YOUR-SERVICE-NAME",
  sampleRate: 40,
});

sdk.start();
You can configure a sample rate for Android traces with .setSampleRate():
// MainApplication.kt
override fun onCreate() {
    val options = HoneycombOpentelemetryReactNativeModule.optionsBuilder(this)
        // Uncomment the line below to send to EU instance. Defaults to US.
        // .setApiEndpoint("https://api.eu1.honeycomb.io:443")
        .setApiKey("YOUR-API-KEY")
        .setServiceName("YOUR-SERVICE-NAME")
        .setSampleRate(40)

    HoneycombOpentelemetryReactNativeModule.configure(this, options)
    super.onCreate()
}

Sending to OpenTelemetry Collector

In production, we recommend running an OpenTelemetry Collector. Your application sends telemetry to your Collector instead of directly to Honeycomb. Your Collector then forwards the telemetry data to Honeycomb, keeping your API key stored securely in the Collector’s configuration. Configure your Collector’s URL by setting the endpoint option when initializing the Honeycomb React Native SDK:
import { HoneycombReactNativeSDK } from '@honeycombio/opentelemetry-react-native';

const sdk = new HoneycombReactNativeSDK({
  endpoint: "http(s)://YOUR-COLLECTOR-URL",
  serviceName: "YOUR-SERVICE-NAME",
});

sdk.start();
This example works for all platforms and shows the core configuration needed to connect your application to a Collector.
For Android, use .setApiEndpoint():
// MainApplication.kt
override fun onCreate() {
    val options = HoneycombOpentelemetryReactNativeModule.optionsBuilder(this)
        .setApiEndpoint("http(s)://YOUR-COLLECTOR-URL")
        .setServiceName("YOUR-SERVICE-NAME")

    HoneycombOpentelemetryReactNativeModule.configure(this, options)
    super.onCreate()
}

Sending to Honeycomb

To send telemetry data directly to Honeycomb, set the apiKey option with your Ingest API Key.
import { HoneycombReactNativeSDK } from '@honeycombio/opentelemetry-react-native';

const sdk = new HoneycombReactNativeSDK({
  apiKey: "YOUR-API-KEY",
  // Uncomment the line below to send to EU instance. Defaults to US.
  // endpoint: "https://api.eu1.honeycomb.io:443",
  serviceName: "YOUR-SERVICE-NAME",
});

sdk.start();
This example works for all platforms and shows the core configuration needed to send data directly to Honeycomb.
For Android, use .setApiKey():
// MainApplication.kt
override fun onCreate() {
    val options = HoneycombOpentelemetryReactNativeModule.optionsBuilder(this)
        // Uncomment the line below to send to EU instance. Defaults to US.
        // .setApiEndpoint("https://api.eu1.honeycomb.io:443")
        .setApiKey("YOUR-API-KEY")
        .setServiceName("YOUR-SERVICE-NAME")

    HoneycombOpentelemetryReactNativeModule.configure(this, options)
    super.onCreate()
}

Adding automatic instrumentation

The Honeycomb OpenTelemetry React Native SDK includes auto-instrumentation options for:
  • Application startup time, measured from when the native SDKs start to when the JavaScript SDK finishes initializing
  • Errors or uncaught exceptions
  • Fetch instrumentation, using the opentelemetry-instrumentation-fetch package
  • Slow event loop detection
Automatic instrumentation is enabled by default. You can enable or disable individual auto-instrumentation libraries in your configuration.
import { HoneycombReactNativeSDK } from '@honeycombio/opentelemetry-react-native';
import { DiagLogLevel } from '@opentelemetry/api';

const sdk = new HoneycombReactNativeSDK({
  // Uncomment the line below to send to EU instance. Defaults to US.
  // endpoint: "https://api.eu1.honeycomb.io:443",
  apiKey: "YOUR-API-KEY",
  serviceName: "YOUR-SERVICE-NAME",
  logLevel: DiagLogLevel.DEBUG,

  // auto-instrumentation options
  reactNativeStartupInstrumentationConfig: {
    enabled: true,
  },

  uncaughtExceptionInstrumentationConfig: {
    enabled: true,
  },

  fetchInstrumentationConfig: {
    enabled: true,
  },

  slowEventLoopInstrumentationConfig: {
    enabled: true,
  },
});

sdk.start();

Adding custom instrumentation

Automatic instrumentation is a fast way to instrument your code, but you get more insight into your application by adding custom, otherwise known as manual, instrumentation.

Adding attributes to an active span

You can retrieve the currently active span in a trace and add attributes to it. This lets you add more context to traces and gives you more ways to group or filter traces in your queries.
import { trace } from '@opentelemetry/api';

function handleUser(user) {
  let currentActiveSpan = trace.getActiveSpan();
  currentActiveSpan.setAttribute('user.id', user.getId());
}

Acquiring a tracer

For manual tracing, you need to get a tracer:
import { trace } from '@opentelemetry/api';

const tracer = trace.getTracer('example-tracer', '0.1.0');

Creating spans

Create custom spans to get a clear view of the critical parts in your application.
import { trace } from '@opentelemetry/api';

function trackWork() {
  const tracer = trace.getTracer('example-tracer', '0.1.0');
  const span = tracer.startActiveSpan('do work');

  console.log('performing work');
  
  span.end();
}

Adding instrumentation to navigation

You can instrument React NativeRouter or Expo Router navigation in your application using the <NavigationInstrumentation> component.

React NativeRouter

Add a <NavigationInstrumentation> component as a child of your <NavigationContainer> component. Pass the container ref to your navigation container and your navigation instrumentation components.
import { NavigationInstrumentation } from '@honeycombio/opentelemetry-react-native';
import { useNavigationContainerRef, NavigationContainer } from '@react-navigation/native';


export default function App() {
  const navigationRef = useNavigationContainerRef();

  return (
    <NavigationContainer ref={navigationRef}>
      <NavigationInstrumentation ref={navigationRef}>
        {/* Navigation/UI code*/}
      </NavigationInstrumentation>
    </NavigationContainer>
  );
}

Expo Router

Wrap your navigation code with a <NavigationInstrumentation> component and pass the container ref to the <NavigationInstrumentation> component.
import { NavigationInstrumentation } from '@honeycombio/opentelemetry-react-native';
import { useNavigationContainerRef } from 'expo-router';


export default function App() {
  const navigationRef = useNavigationContainerRef();

  return (
    <NavigationInstrumentation ref={navigationRef}>
      {/* Navigation/UI code*/}
    </NavigationInstrumentation>
  );
}

Troubleshooting

Running into issues? Here are some common problems and ways to fix them. To explore common issues when sending data, visit Common Issues with Sending Data in Honeycomb.

File not found error on iOS

If you see an error like this when running your application on iOS:
'HoneycombOpentelemetryReactNative/HoneycombOpentelemetryReactNative-Swift.h' file not found when trying to run for iOS
It usually means your application’s Podfile is missing the use_frameworks! line. To resolve this error:
  1. Add use_frameworks! immediately below prepare_react_native_project! in your Podfile:
    prepare_react_native_project!
    use_frameworks!
    
  2. Install the iOS dependencies by navigating to your ios directory and running pod install:
    cd ios
    pod install
    

Not receiving native telemetry data

Unlike JavaScript code, native code does not hot reload on changes. So if you updated your AppDelegate.swift or MainApplication.kt files and still not getting native telemetry you’ll need to rebuild your application. Stop metro, the simulator, and restart the build. If this still doesn’t work try uninstalling the app and reinstalling it.