APNs authorization token generation
Generate an APNs authorization token (JSON Web Token) using your Apple Team ID, APN key (.p8 file), and Key ID:
```js
const jwt = require("jsonwebtoken");
const authorizationToken = jwt.sign(
{
iss: "YOUR-APPLE-TEAM-ID",
iat: Math.round(new Date().getTime() / 1000),
},
fs.readFileSync("./path/to/appName_apns_key.p8", "utf8"),
{
header: {
alg: "ES256",
kid: "YOUR-P8-KEY-ID",
},
}
);
```
APNs HTTP/2 connection endpoints
After obtaining authorization token, open HTTP/2 connection to Apple's APNs servers. In development, connect to https://api.sandbox.push.apple.com. In production, connect to https://api.push.apple.com.
getDevicePushTokenAsync for direct FCM/APNs notifications
When sending notifications directly via FCM or APNs instead of through Expo's notification service, obtain the native device token using getDevicePushTokenAsync() and access it via the .data property of the returned promise.
Creating Headless Background Notifications with Expo Push Service
When using the Expo Push Service, specifying only data and contentAvailable: true (and other non-interactive fields such as ttl) results in a Headless Background Notification.
Notification interaction response handlers by app state
When the user interacts with a notification by pressing an action button: On iOS in any state (foreground, background, or terminated), NotificationResponseReceivedListener is triggered. On Android in foreground, NotificationResponseReceivedListener is triggered; in background, both NotificationResponseReceivedListener and JS task are triggered; when terminated, only JS task is triggered. When NotificationResponseReceivedListener is triggered, the useLastNotificationResponse return value also changes.
Registering NotificationResponseReceivedListener on app startup
When the app is not running or has been killed and is launched by tapping a notification, register NotificationResponseReceivedListener as early as possible at module top-level on iOS. To handle the initial notification response after the app starts, it is recommended to check useLastNotificationResponse or getLastNotificationResponse during startup rather than relying on the listener alone. This is also the recommended approach for action buttons that bring the app to the foreground.
iOS background notification configuration requirement
To use Headless Background Notifications on iOS, you must configure them first.
Data-only notification terminology
Android has Data Messages which are notifications that contain only data. iOS does not have the exact same concept but the close equivalent is Headless Background Notifications. The term 'silent notification' is another name for notifications that do not present anything to the user, which refers to Headless Background Notifications.
Headless notification with title or message in data field behavior
When you specify title or message inside the data field, expo-notifications package automatically presents the headless notification on Android, but not on iOS. The behavior is planned to be made more consistent across platforms in a future release.
Expo notifications built on native platform functionality
Expo's notification support builds on top of the native functionality provided by Android and iOS. The same concepts and behaviors from native platforms apply to Expo apps.
Headless Background Notifications definition
Headless Background Notifications are remote notifications that do not directly specify presentational information such as title or body text. They are not presented to users. Instead, they carry JSON data which is processed by a JavaScript task defined via registerTaskAsync. The task may perform arbitrary logic such as writing to AsyncStorage, making API requests, or presenting a local notification. On Android, these correspond to Data Messages. On iOS, these correspond to background notifications.
Push vs Local notifications in Expo
Push Notifications (also called remote notifications) are sent to a user's device from a remote server. Local Notifications (also called in-app notifications) are created and displayed from within the app. Scheduled notifications may also be called local notifications since they are created at a particular time. The expo-notifications package supports both push and local notifications.
Expo Go limitation for push notifications
You must use a development build to use push notifications since the capability is not built into Expo Go.
App foreground state and notification handling
When a push notification arrives and the app is in the foreground, the app is in control of how the incoming notification is handled. The app may present it directly, show custom in-app UI, or ignore it. This behavior is controlled by NotificationHandler.
Application states for push notifications
Foreground: The app is actively running and its interface is displayed on screen. Background: The app is minimized and its interface is not displayed on screen. Terminated: The app was killed, usually by a swipe-away gesture in the app switcher. On Android, if the user force-stops the app from device settings, it must be manually reopened for notifications to start working.
Notification Message definition and behavior
A Notification Message is a notification that specifies presentational information such as title or body text. On Android, this contains AndroidNotification. On iOS, this contains aps.alert dictionary with apns-push-type header set to alert. When using Expo Push Service and specifying title, subtitle, body, icon, or channelId, the resulting push notification request is a Notification Message. The typical use case is to have it presented to the user immediately.
Notification Message with data payload (Android-only)
A Notification Message with data payload is an Android-only term where a push notification request contains both data field and notification field. On iOS, extra data may be part of a regular Notification Message request, but Apple does not distinguish between Notification Messages with and without data.
Headless Background Notification delivery guarantee limitation
Headless Background Notifications have the ability to run custom JavaScript even when the app is terminated, but the OS does not guarantee delivery to the app. This may occur due to reasons such as Doze mode on Android or rate limiting on Apple (Apple recommends not sending more than two or three per hour).
Push notifications require FCM credentials setup
To test push notifications with Expo, you must configure FCM credentials as documented at https://docs.expo.dev/push-notifications/fcm-credentials/, plus you need a developer account for iOS.
Notification Message Delivery Behavior
Notification delivery behavior depends on the app state and notification type:
**Regular Notifications** (Notification Message and Notification Message with data payload):
- When the app is in the foreground: delivery runs NotificationReceivedListener and JS task
- When the app is in the background or terminated: the OS shows the notification to the user
**Headless Background Notifications:**
- When the app is in the foreground: delivery runs NotificationReceivedListener and JS task
- When the app is in the background or terminated: delivery runs JS task
Expo push notifications rate limit
Expo push notifications are limited to 600 notifications per second per project. If you exceed this rate, subsequent requests will fail until the rate falls below 600 per second again. The expo-server-sdk-node library handles throttling automatically, and adding throttling and retry logic to your server is recommended for best results.