> AI agents: this is one page from PostHog's docs. Full index of Markdown docs for LLMs: https://posthog.com/llms.txt

# React Native push notifications - Docs

Copy page

# React Native push notifications - Docs

Set up [Workflows](/docs/workflows.md) push notifications in the React Native SDK. For the concept and channel setup, see [Push notifications](/docs/workflows/push-notifications.md).

Available in `posthog-react-native` 4.62.0 and newer, and requires the optional [`@posthog/react-native-plugin`](https://www.npmjs.com/package/@posthog/react-native-plugin) package (2.3.0+). Not supported on React Native Web or macOS.

## Requirements

Configure push in your app as usual (for example with `@react-native-firebase/messaging`) and request notification permission from the user.

## Automatic registration and open tracking (default)

Both behaviors are on by default. An app that already has push configured and the plugin installed starts sending its device token to PostHog after upgrading, with no code change:

React Native

PostHog AI

```jsx
<PostHogProvider
    apiKey="<ph_project_token>"
    options={{
        host: 'https://us.i.posthog.com',
        // Both default to true, shown here for clarity:
        capturePushNotificationSubscriptions: true, // register the device token with PostHog
        capturePushNotificationOpened: true,        // capture `$push_notification_opened` on tap
    }}
>
    <MyComponent />
</PostHogProvider>
```

On iOS the native SDK hooks the app delegate's remote-notification registration callback, so it picks up the APNs token once your app registers for remote notifications. On Android it fetches the FCM token at startup when Firebase Messaging is on the classpath (`@react-native-firebase/messaging` sets this up). The token is registered under the current distinct ID, so it follows the user across `identify()`.

Open coverage differs per platform. On iOS every tap on a remote notification is captured whatever the app state; locally-scheduled notifications are ignored. On Android only cold-start taps are captured. Capture the rest manually (below).

The Android startup fetch doesn't see later token refreshes, so forward those yourself to keep the registered token current:

React Native

PostHog AI

```jsx
import messaging from '@react-native-firebase/messaging'
import { Platform } from 'react-native'
if (Platform.OS === 'android') {
    messaging().onTokenRefresh((token) => posthog.registerPushNotificationToken(token))
}
```

## Manual registration

If you manage push tokens yourself, turn the automatic flags off and call the SDK directly:

React Native

PostHog AI

```jsx
// Register the device token. Pass appId to route to a specific channel
// (your Firebase project id, or APNs bundle id on iOS):
await posthog.registerPushNotificationToken(token, { appId: 'your-firebase-project-id' })
```

It's safe to call this before the SDK finishes initializing; the call is queued rather than dropped.

When `appId` is unset, iOS registers the token as an APNs token under your bundle id and Android as an FCM token under your default Firebase project id. To use FCM on iOS instead, set `capturePushNotificationSubscriptions: false` and pass your Firebase project id as `appId`, otherwise the device registers twice (once per provider) and a Workflow connected to both channels delivers twice.

Unregister the token when a user signs out so it isn't left bound to them:

React Native

PostHog AI

```jsx
await posthog.unregisterPushNotificationToken()
```

Calling `posthog.reset()` on logout already moves the registered token to the new anonymous identity, so this is only needed when you manage subscriptions yourself.

Registration and unregistration are durable. If the device is offline or the request fails, the SDK retries on the next flush, identity change, or app launch.

## Capturing opens

For the opens automatic capture misses (locally-scheduled notifications on either platform, plus warm-start taps and foreground messages on Android), call the manual API:

React Native

PostHog AI

```jsx
import messaging from '@react-native-firebase/messaging'
import { Platform } from 'react-native'
if (Platform.OS === 'android') {
    messaging().onNotificationOpenedApp((message) => {
        posthog.capturePushNotificationOpened({
            title: message.notification?.title,
            body: message.notification?.body,
            payload: message.data,
        })
    })
}
```

Only call it for opens automatic capture can't see itself, or the tap is counted twice.

The `$push_notification_opened` event includes `$notification_title` and `$notification_body` (plus `$notification_subtitle` on iOS), and `$notification_action` for action-button taps. Notification content is only captured for notifications sent by PostHog. Opens of other notifications are still captured, but without title or body.

The event is built and sent by the native SDK, so your JS `before_send` never sees it. Redact anything sensitive before passing it to `capturePushNotificationOpened`.

## Opting out

Set `capturePushNotificationSubscriptions: false` or `capturePushNotificationOpened: false` in the initialization options.

## Identity verification

If your push channel requires [identity verification](/docs/workflows/push-notifications.md#identity-verification), supply a backend-minted token through `pushIdentityProvider`:

React Native

PostHog AI

```jsx
<PostHogProvider
    apiKey="<ph_project_token>"
    options={{
        host: 'https://us.i.posthog.com',
        pushIdentityProvider: async (distinctId, appId) => {
            // Fetch a freshly-minted token from your backend for this user, then:
            return token // or null to send without one
        },
    }}
>
    <MyComponent />
</PostHogProvider>
```

## Troubleshooting

| Issue | Check |
| --- | --- |
| Token never registers | Confirm @posthog/react-native-plugin is installed, push is set up in your app, and the user granted notification permission. On Android, confirm Firebase Messaging is on the classpath (@react-native-firebase/messaging sets this up). |
| Push doesn't arrive | Confirm the channel's Firebase project (Android) or APNs environment and bundle id (iOS) match your app. |
| Registration rejected on a Required channel | Your pushIdentityProvider isn't returning a valid token in time. See [Identity verification](/docs/workflows/push-notifications.md#identity-verification). |

### Was this page useful?

HelpfulCould be better