> AI agents: this is one page from PostHog's docs. Full index of Markdown docs for LLMs: https://posthog.com/llms.txt # Push notifications PostHog mobile SDKs can register a device for [Workflows](/docs/workflows.md) push notifications and capture when a user opens one. Sends go out through the FCM or APNs channel you connect in [Workflows > Channels](/docs/workflows/configure-channels?tab=Push.md). **Push notifications are in open beta** Push is in open beta. It's available in every project, so you don't need to request access. Each send counts toward your workflows destinations usage and quota. To send feedback, [reach out in-app](https://app.posthog.com/#panel=support%3Afeedback%3A%3Alow%3Atrue). **What the SDK does and doesn't do** The SDK registers the device token with PostHog and captures opens. You still own the platform setup: set up remote notifications (for example with Firebase Cloud Messaging) and request notification permission from the user. The SDK doesn't do that for you. ## Requirements - A connected **FCM** or **APNs** channel in PostHog whose Firebase project (FCM) or bundle id (APNs) matches your app. See [Configure a workflows channel](/docs/workflows/configure-channels?tab=Push.md). - Platform push set up in your app and notification permission requested from the user. ## Set up Follow the guide for your SDK: - [iOS](/docs/workflows/push-notifications/ios.md) - [Android](/docs/workflows/push-notifications/android.md) - [React Native](/docs/workflows/push-notifications/react-native.md) - [Flutter](/docs/workflows/push-notifications/flutter.md) ## Identity verification A device token says *where* to deliver a notification, not *who* the device belongs to. If you turn on identity verification for your push channel ([Optional or Required](/docs/workflows/configure-channels?tab=Push.md)), your app must attach a short-lived token that proves the logged-in user's identity when it registers a device. Your **backend** mints that token. The SDK never signs one itself. Generate an EC (P-256) key pair, keep the private key on your backend, and paste the public key into the channel's **Public key** field when you turn on identity verification. Your backend signs an ES256 JWT with the private key, with the user's `distinct_id` as `sub`, the `appId` your provider receives as `app_id` (your Firebase project ID or APNs bundle ID), `aud` set to `posthog:push_identity`, and a short `exp`. PostHog verifies the token with the public key you registered, so the private key never leaves your control. Generate the key pair once with any standard tool, for example openssl: Terminal ```bash openssl ecparam -name prime256v1 -genkey -noout -out push-identity-private.pem # keep this on your backend openssl ec -in push-identity-private.pem -pubout -out push-identity-public.pem # paste this into the Public key field ``` Your app supplies the token through a `pushIdentityProvider` callback. See the per-platform guide above for the exact signature. Notes: - Registration verifies the token against the public key you registered, so a token signed with any other private key is rejected with a 401. - If you leave the **Public key** field blank, registration instead verifies the token against your project's Feature flags secure API key (Settings → Feature flags) using HS256, a shared secret you sign with directly. The public key flow is preferred because the signing key stays on your backend. - The SDK calls your provider when it needs a token and caches the result in memory per `(distinctId, appId)`, re-requesting on identity change and when a request is rejected. Always call the completion exactly once. - If your provider doesn't respond in time (10 seconds), the SDK falls back to sending without a token. On a channel set to **Required** that request is rejected, so make sure your provider reliably returns a token before switching the channel to Required. ### Still have questions? Ask PostHog AI ### Was this page useful? HelpfulCould be better