> ## Documentation Index
> Fetch the complete documentation index at: https://docs.honeycomb.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Instrument React Native Applications with OpenTelemetry

> Instrument your React Native application with the Honeycomb OpenTelemetry React Native SDK to detect slow renders and send telemetry to Honeycomb.

The [Honeycomb OpenTelemetry React Native SDK](https://github.com/honeycombio/honeycomb-opentelemetry-react-native) 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](https://github.com/honeycombio/honeycomb-opentelemetry-react-native/tree/main/example).

## 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](https://reactnative.dev/blog/2023/06/21/package-exports-support) in your Metro configuration.

   ```js theme={}
   config.resolver.unstable_enablePackageExports = true;
   ```

   Here's an [example Metro configuration](https://github.com/honeycombio/honeycomb-opentelemetry-react-native/blob/main/example/metro.config.js):

   ```js theme={}
   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;
   ```

   <Tip>
     To learn more about Metro configuration, visit [Configuring Metro](https://metrobundler.dev/docs/configuration/).
   </Tip>

2. Install Honeycomb’s OpenTelemetry React Native SDK in your application’s root directory using your preferred package manager.

   <Tabs>
     <Tab title="npm">
       ```bash theme={}
       npm install @honeycombio/opentelemetry-react-native
       ```
     </Tab>

     <Tab title="yarn">
       ```bash theme={}
        yarn add @honeycombio/opentelemetry-react-native
       ```
     </Tab>
   </Tabs>

3. Install the necessary dependencies for each mobile platform your application supports.

   <Tabs>
     <Tab title="Android">
       Add the following dependencies to your application's `build.gradle`.

       ```gradle theme={}
       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](https://developer.android.com/studio/write/java8-support#library-desugaring) to your `android/app/build.gradle`.

       ```gradle theme={}
       android {
           compileOptions {
               // Enable support for the new language APIs
               coreLibraryDesugaringEnabled true
           }
           dependencies {
               coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.1.5"
           }
       }
       ```
     </Tab>

     <Tab title="iOS">
       Add the `use_frameworks!` option to your application's `Podfile`.

       ```podfile theme={}
       platform :ios, min_ios_version_supported
       prepare_react_native_project!
       use_frameworks!
       ```

       From the `ios` directory, run `pod install` to install the required dependencies.
     </Tab>
   </Tabs>

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

```ts theme={}
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();
```

<Tabs>
  <Tab title="Android">
    Initialize the SDK at the start of the `onCreate()` method in your main `Application` class.

    ```kotlin theme={}
    // 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()
    }
    ```
  </Tab>

  <Tab title="iOS">
    Initialize the SDK at the start of the `application()` method in your `AppDelegate` class.

    ```swift theme={}
    // AppDelegate.swift
    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
    ) -> Bool {
        let options = HoneycombReactNative.optionsBuilder()
            // 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")

        HoneycombReactNative.configure(options)
    }
    ```
  </Tab>
</Tabs>

## Configuring

The Honeycomb React Native SDK can be configured using many of the [configuration options from the Honeycomb Web SDK](https://github.com/honeycombio/honeycomb-opentelemetry-web/tree/main/packages/honeycomb-opentelemetry-web#sdk-configuration).

```ts theme={}
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.

```ts theme={}
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](/manage-data-volume/sample/).
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.

```ts theme={}
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();
```

<Tabs>
  <Tab title="Android">
    You can configure a sample rate for Android traces with `.setSampleRate()`:

    ```kotlin theme={}
    // 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()
    }
    ```
  </Tab>

  <Tab title="iOS">
    You can configure a sample rate for iOS traces with `.sampleRate()`:

    ```swift theme={}
    // AppDelegate.swift
    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
    ) -> Bool {
        let options = HoneycombReactNative.optionsBuilder()
            // 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")
            .sampleRate(40)

        HoneycombReactNative.configure(options)
    }
    ```
  </Tab>
</Tabs>

### Sending to OpenTelemetry Collector

In production, we recommend running an [OpenTelemetry Collector](/send-data/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:

```ts theme={}
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.

<Tabs>
  <Tab title="Android">
    For Android, use `.setApiEndpoint()`:

    ```kotlin theme={}
    // 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()
    }
    ```
  </Tab>

  <Tab title="iOS">
    For iOS, use `.setAPIEndpoint()`:

    ```swift theme={}
    // AppDelegate.swift
    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
    ) -> Bool {
        let options = HoneycombReactNative.optionsBuilder()
            .setAPIEndpoint("http(s)://YOUR-COLLECTOR-URL")
            .setServiceName("YOUR-SERVICE-NAME")

        HoneycombReactNative.configure(options)
    }
    ```
  </Tab>
</Tabs>

### Sending to Honeycomb

To send telemetry data directly to Honeycomb, set the `apiKey` option with your [Ingest API Key](/configure/environments/manage-api-keys/#create-api-key).

```ts theme={}
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.

<Tabs>
  <Tab title="Android">
    For Android, use `.setApiKey()`:

    ```kotlin theme={}
    // 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()
    }
    ```
  </Tab>

  <Tab title="iOS">
    For iOS, use `.setAPIKey()`:

    ```swift theme={}
    // AppDelegate.swift
    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
    ) -> Bool {
        let options = HoneycombReactNative.optionsBuilder()
            // 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")

        HoneycombReactNative.configure(options)
        //...
    }
    ```
  </Tab>
</Tabs>

## Adding automatic instrumentation

The Honeycomb OpenTelemetry React Native SDK includes [auto-instrumentation options](https://github.com/honeycombio/honeycomb-opentelemetry-react-native/tree/main?tab=readme-ov-file#auto-instrumentation) for:

* Application startup time, measured from when the native SDKs start to when the JavaScript SDK finishes initializing
* Errors or uncaught exceptions
* [Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch) instrumentation, using the [opentelemetry-instrumentation-fetch](https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/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.

```ts theme={}
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.

```ts theme={}
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:

```ts theme={}
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.

```ts theme={}
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](https://reactnavigation.org/docs/navigation-container/#ref) to your navigation container and your navigation instrumentation components.

```ts theme={}
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.

```ts theme={}
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](/troubleshoot/common-issues/sending-data/#opentelemetry-sdks-and-honeycomb-distributions).

### File not found error on iOS

If you see an error like this when running your application on iOS:

```text theme={}
'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`:

   ```swift theme={}
   prepare_react_native_project!
   use_frameworks!
   ```

2. Install the iOS dependencies by navigating to your `ios` directory and running `pod install`:

   ```bash theme={}
   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.
