npm package: @openpanel/react-native
Description: > 📖 **Full documentation:** [https://openpanel.dev/docs/sdks/react-native](https://openpanel.dev/docs/sdks/react-native)
Latest version: 1.4.0

# React Native

> 📖 **Full documentation:** [https://openpanel.dev/docs/sdks/react-native](https://openpanel.dev/docs/sdks/react-native)

---

Looking for a step-by-step tutorial? Check out the [React Native analytics guide](https://openpanel.dev/guides/react-native-analytics).

## Installation

### Install dependencies

We're dependent on `expo-application` for `buildNumber`, `versionNumber` (and `referrer` on android) and `expo-constants` to get the `user-agent`.

```npm
npm install @openpanel/react-native
npx expo install expo-application expo-constants
```

### Initialize

On native we use a clientSecret to authenticate the app.

```typescript
import { OpenPanel } from '@openpanel/react-native';

const op = new OpenPanel({
  clientId: '{YOUR_CLIENT_ID}',
  clientSecret: '{YOUR_CLIENT_SECRET}',
});
```

#### Options

##### Common options

- `apiUrl` - The url of the openpanel API or your self-hosted instance
- `clientId` - The client id of your application
- `clientSecret` - The client secret of your application (**only required for server-side events**)
- `filter` - A function that will be called before sending an event. If it returns false, the event will not be sent
- `disabled` - If true, the library will not send any events

## Usage

### Track event

```typescript
op.track('my_event', { foo: 'bar' });
```

### Navigation / Screen views

  
#### expo-router

```typescript
    import { usePathname, useSegments } from 'expo-router';

    const op = new Openpanel({ /* ... */ })

    function RootLayout() {
      // ...
      const pathname = usePathname()
      // Segments is optional but can be nice to have if you
      // want to group routes together
      // pathname = /posts/123
      // segements = ['posts', '[id]']
      const segments = useSegments()

      useEffect(() => {
        // Simple
        op.screenView(pathname)

        // With extra data
        op.screenView(pathname, {
          // segments is optional but nice to have
          segments: segments.join('/'),
          // other optional data you want to send with the screen view
        })
      }, [pathname,segments])
      // ...
    }
    ```

  
#### react-navigation (simple)

```tsx
      import { createNavigationContainerRef } from '@react-navigation/native'
      import { Openpanel } from '@openpanel/react-native'

      const op = new Openpanel({ /* ... */ })
      const navigationRef = createNavigationContainerRef()

      export function NavigationRoot() {
        const handleNavigationStateChange = () => {
          const current = navigationRef.getCurrentRoute()
          if (current) {
            op.screenView(current.name, {
              params: current.params,
            })
          }
        }

        return (
          <NavigationContainer
            ref={navigationRef}
            onReady={handleNavigationStateChange}
            onStateChange={handleNavigationStateChange}
          >
            <Stack.Navigator />
          </NavigationContainer>
        )
      }
    ```

For more information on how to use the SDK, check out the [Javascript SDK](https://openpanel.dev/docs/sdks/javascript#usage).

## Offline support

The SDK can buffer events when the device is offline and flush them once connectivity is restored. Events are stamped with a `__timestamp` at the time they are fired so they are recorded with the correct time even if they are delivered later.

Two optional peer dependencies enable this feature:

```npm
npm install @react-native-async-storage/async-storage @react-native-community/netinfo
```

Pass them to the constructor:

```typescript
import { OpenPanel } from '@openpanel/react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import NetInfo from '@react-native-community/netinfo';

const op = new OpenPanel({
  clientId: '{YOUR_CLIENT_ID}',
  clientSecret: '{YOUR_CLIENT_SECRET}',
  // Persist the event queue across app restarts
  storage: AsyncStorage,
  // Automatically flush the queue when the device comes back online
  networkInfo: NetInfo,
});
```

Both options are independent — you can use either one or both:

- **`storage`** — persists the queue to disk so events survive app restarts while offline.
- **`networkInfo`** — flushes the queue automatically when connectivity is restored. Without this, the queue is flushed the next time the app becomes active.