# React Native

URL: https://pieowl.com/docs/sdks/react-native







<Callout>
  Looking for a step-by-step tutorial? Read the [React Native analytics guide](/guides/react-native-analytics).
</Callout>

Installation [#installation]

<Steps>
  Install dependencies [#install-dependencies]

  The SDK uses `expo-application` for the app version and build number (and the install referrer on Android), and `expo-constants` to get the user agent.

  <CodeBlockTabs defaultValue="npm">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="npm">
        npm
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="pnpm">
        pnpm
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="yarn">
        yarn
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="bun">
        bun
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="npm">
      ```bash
      npm install @pieowl/react-native
      npx expo install expo-application expo-constants
      ```
    </CodeBlockTab>

    <CodeBlockTab value="pnpm">
      ```bash
      npm install @pieowl/react-native
      pnpm dlx expo install expo-application expo-constants
      ```
    </CodeBlockTab>

    <CodeBlockTab value="yarn">
      ```bash
      npm install @pieowl/react-native
      yarn dlx expo install expo-application expo-constants
      ```
    </CodeBlockTab>

    <CodeBlockTab value="bun">
      ```bash
      npm install @pieowl/react-native
      bun x expo install expo-application expo-constants
      ```
    </CodeBlockTab>
  </CodeBlockTabs>

  Initialize [#initialize]

  Native apps can't send CORS headers, so the SDK authenticates with your client secret.

  ```typescript
  import { Pieowl } from '@pieowl/react-native';

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

  Options [#options]

  <CommonSdkConfig />
</Steps>

Usage [#usage]

Track event [#track-event]

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

Navigation and screen views [#navigation-and-screen-views]

<Tabs items="['expo-router', 'react-navigation (simple)']">
  <Tab value="expo-router">
    ```typescript
    import { usePathname, useSegments } from 'expo-router';

    const pieowl = new Pieowl({ /* ... */ })

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

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

        // With extra data
        pieowl.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])
      // ...
    }
    ```
  </Tab>

  <Tab value="react-navigation (simple)">
    ```tsx
      import { createNavigationContainerRef } from '@react-navigation/native'
      import { Pieowl } from '@pieowl/react-native'

      const pieowl = new Pieowl({ /* ... */ })
      const navigationRef = createNavigationContainerRef()

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

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

For all other methods, see the [JavaScript SDK](/docs/sdks/javascript#usage).

Offline support [#offline-support]

The SDK can hold events while the device is offline and send them when it's back online. Each queued event gets a timestamp when it fires, so it's recorded at the right time even if it arrives later.

Two optional peer dependencies enable this feature:

<CodeBlockTabs defaultValue="npm">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="npm">
      npm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="pnpm">
      pnpm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="yarn">
      yarn
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="bun">
      bun
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="npm">
    ```bash
    npm install @react-native-async-storage/async-storage @react-native-community/netinfo
    ```
  </CodeBlockTab>

  <CodeBlockTab value="pnpm">
    ```bash
    pnpm add @react-native-async-storage/async-storage @react-native-community/netinfo
    ```
  </CodeBlockTab>

  <CodeBlockTab value="yarn">
    ```bash
    yarn add @react-native-async-storage/async-storage @react-native-community/netinfo
    ```
  </CodeBlockTab>

  <CodeBlockTab value="bun">
    ```bash
    bun add @react-native-async-storage/async-storage @react-native-community/netinfo
    ```
  </CodeBlockTab>
</CodeBlockTabs>

Pass them to the constructor:

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

const pieowl = new Pieowl({
  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,
});
```

What each option does:

* **`networkInfo`** — tells the SDK when the device goes offline, so events are queued instead of sent, and sends the queue as soon as the device is back online.
* **`storage`** — saves the queue to disk, so queued events survive an app restart.

The SDK also tries to send the queue each time the app becomes active.
