Upcoming changes to the Expo push notification service (Summer 2018)

We’re making several changes to the Expo push notification service, the server side of the Expo Push Notifications API. Learn about the changes and how to update your projects.

Over the next few months, we’ll be making a series of changes to the Expo push notification service to improve reliability and overall performance. If you use the Expo push notification service in your project (e.g. sending notifications to the HTTP/2 API, or using the Node expo-server-sdk library), read this post to learn about the changes to make to your project.

The major updates are:

  • Gracefully rate-limiting notifications (now)
  • Asynchronously providing push receipts (mid-July)
  • Requiring FCM for new Android apps (mid-July)
  • Requiring the modern batch notification API (October 1)
  • Recommending against using unregistered push tokens (ongoing)

Gracefully rate-limiting notifications (June)

We see that developers send large numbers of notifications at once, and sometimes these sudden spikes in load (streams to Apple and Google, CPU, and database connections) degrade our server cluster performance. Our servers are generally self-healing, but this can take several minutes and, in the meantime, notifications and other requests are much more likely to encounter errors.

To make these errors more deterministic, we’re adding a gentle form of rate limiting. When the Expo push notification service is under high load, it will send back error receipts with:

{"details": { "error": "MessageRateExceeded" } }

This is the same way we treat rate limiting from Apple and Google’s underlying notification services; there are no API changes. We also don’t limit the total number of notifications you can send. This rate limiting is just to improve the reliability of Expo services for everyone.

How to Update

We recommend implementing the following two strategies to handle MessageRateExceeded errors, if you haven’t yet already:

  • Implement truncated exponential backoff. 
    If you receive push receipts with MessageRateExceeded errors, update your code to wait one second before sending more notifications. After a second, retry sending the notifications that weren’t delivered. If you still receive push receipts with MessageRateExceeded errors, wait two seconds and try again. Keep exponentially increasing the cool-down time between retries until they succeed.
  • Proactively limit the number of concurrent requests to the Expo push notification service. 
    If you’re sending many thousands of push notifications all at once, space out your requests to the Expo push notification service. Specifically, instead of making hundreds or thousands of HTTP requests at once, send a few at a time and wait for one to complete before sending another. If you use the Node expo-server-sdk package, you can upgrade to version 2.4.0, which has concurrency limiting built in.

Timeline

We’ll deploy this rate limiting in a day or two. We expect this to be a non-disruptive change because we already try to send back MessageRateExceeded errors when the service would have otherwise failed to deliver notifications anyway. Additionally, the MessageRateExceeded error has been part of the Expo push notification service API for over a year (since Apple or Google have their own rate limiting), so there’s no change to our API.


Asynchronously providing push receipts (mid-July)

Currently, the Expo push notification service API returns a “receipt” for each notification sent. A receipt, which is documented in the Expo push notification API guide, communicates whether a notification was successfully delivered to Apple (APNs) or Google (GCM and FCM), or if there was an error. (Note: a receipt doesn’t indicate whether the device successfully received the notification; this is how mobile push notifications work in general.) In the near future, we will be making two changes to push receipts: new semantics for the current push receipts, and a new endpoint for asynchronous push receipts.

  • Immediate push receipts: The first change is that the current push receipts — the ones in the response of the HTTP request to send notifications — will report whether Expo successfully received the notifications and enqueued them for delivery. They will no longer convey Apple or Google’s acknowledgement of the notification.
  • Asynchronous push receipts: The second change is that there’ll be a new HTTP/2 API endpoint to asynchronously get receipt of the delivery to Apple or Google. If there are problems with your push notification credentials or if Apple or Google has unregistered a device token, the asynchronous push receipt will contain the corresponding error.

These changes will improve the stability of the Expo push notification service by allowing us more time to deliver notifications to Apple and Google.

How to Update

When the asynchronous API is ready, we’ll update the HTTP/2 push notification service API documentation with information about the new endpoint. We’ll also publish a new version of the Node expo-server-sdk library with a method call to query this endpoint.

If you don’t update right away, push notifications will mostly continue to work. However, to get the delivery status of each notification you’ll need to query the new asynchronous receipt endpoint so we recommend updating as soon as you find yourself able.

Timeline

The new asynchronous API, and the service behind it, is currently in development. We plan to deploy it in next week or so for push notifications sent to the Expo client only (that is, no standalone apps at first). Afterwards, we will deploy it to standalone apps.


Requiring FCM for new Android apps (mid-July)

For Android devices, the Expo push notification service supports both Google Cloud Messaging (GCM) and Firebase Cloud Messaging (FCM) as the underlying services used to deliver notifications. FCM is the more modern of the two, and Google has announced they’re removing GCM next year. Additionally, we’ve noticed that GCM has been unregistering device tokens for standalone apps at very high rates. We highly recommend that all developers creating standalone apps configure their projects to use FCM today to address these issues.

How to Update

To use FCM, you’ll need to use SDK 27 or later and create a Firebase project (free is OK) for your Android app and associate your Expo project with it. You’ll also need to upload your FCM API key to Expo so the Expo push notification service can send notifications to your app. Finally, you’ll need to update your app in Google Play if you’ve published your APK before. Everyone who downloads the new APK will begin using FCM when you get a new Expo push token with Expo.Notifications.getExpoPushTokenAsync. (Note: this token will be different from the one returned when the app was using GCM.)

All of the necessary steps are explained in the guide, “Using FCM for Push Notifications”. After updating your app and uploading the FCM API key, you’ll still use the same Expo push notification service, but Expo will now use FCM, rather than GCM, underneath.

Timeline

Starting sometime in mid-July, we’ll require that all new Expo apps use FCM. Existing apps can continue to use the legacy service based on GCM, though we do recommend updating to use FCM when you upgrade your app to use SDK 27 or later.


Requiring the batch notification API (October 1)

The Expo push notification service supports two HTTP-based APIs: a legacy one that doesn’t support batching together multiple notifications, and a modern one that does. Batching notifications together reduces the number of HTTP requests you need to make when sending larger numbers of notifications and also lets us more easily coalesce cache and database requests inside of the Expo push notification service.

Most developers are already using the modern batch notification API. If you are using version 2.x of the Node expo-server-sdk or have written your own client that connects to the documented HTTP/2 API, you’re already using the modern API. The modern API has been in production since February 2017, and the legacy API has been sending back deprecation messages since the beginning of this year.

How to Update

If you’re using the Node expo-server-sdk library, upgrade to the latest version. If you’re using another client that you didn’t write, read its documentation or source code to see the Expo server URL it uses; the modern batch API is at https://exp.host/--/api/v2/push/send.

Timeline

The legacy API currently sends back deprecation messages that say, “This is Expo’s legacy push notification endpoint,” followed by some guidance. On October 1, 2018, we will disable this endpoint and it will begin sending back HTTP errors.


Recommending against using unregistered push tokens (ongoing)

When a device token is no longer eligible to receive push notifications, the underlying notification delivery service operated by Apple or Google will eventually unregister the token. This can happen for several reasons: because the user uninstalls your app, because the user revokes permission to send push notifications, or for any other reason that Apple or Google decides based on their services’ policies. (Note: a device token can remain registered for awhile after uninstalling an app. The device will not display the notification, however.) When Apple or Google reports back to Expo that a device token has been unregistered, we include theDeviceNotRegistered error in push receipts for notifications sent to that device token.

When you receive a push receipt with the DeviceNotRegistered error, you should stop sending notifications with the respective Expo push token. This is so Apple or Google don’t take adverse action against your app. In practice, they are lenient and we’ve found it OK to send several notifications to unregistered device tokens, but we advise removing device tokens once you’ve learned that they’re unregistered.

How to update

Expo is not making any API changes. If you already remove unregistered device tokens from your database, you don’t have to do anything.


These are the updates we have in store for the Expo push notification service. We’re working to improve its stability for developers like you in the near future.