AMS.

My first Expo push notifications: device tokens, Expo tokens, APNs and where EAS fits

5 min listen

Cover: Mount Pisgah, NC radio tower, October 2016 by Thomson200, CC0 1.0.

Background

I assumed a push notification went from one phone straight to another. I also thought it was an EAS service that would eat my free quota. When the build asked "Set up Push Notifications?", I wasn't even sure whether to say yes.

What I tried

  • Thinking phones send to each other: a phone never connects directly to another phone.
  • Thinking Expo and EAS were the same thing: the names get used interchangeably, so I assumed pushes counted against EAS quotas.
  • Treating APNs as a certificate: half right, but I didn't know who actually checks it.

How I did it

1. Tell the two tokens apart

  • Device token: issued by Apple and tied to "this phone and this app". It's the phone's address on Apple's side.
  • Expo push token: looks like ExponentPushToken[...]. Expo wraps the device token and gives you this instead. iOS and Android use the same format, so the backend doesn't need two code paths.

Once the user allows notifications, the app gets its Expo push token and sends it to the backend to store. This happens once.

2. Sending is a relay

  1. When the backend has something to say, it sends the token and message to Expo's push API.
  2. Expo swaps the Expo token for Apple's device token.
  3. Expo uses your APNs key to hand the notification to Apple.
  4. Apple delivers it. An iPhone keeps an encrypted connection to Apple open, so it arrives even with the app closed.
My backend sendsitExpo push serviceApple's pushserviceThe user's iPhonedevice token
How a push reaches the phone

The backend only makes one HTTP request, for example:

[
  { "to": "ExponentPushToken[xxxxxxxx]", "title": "Hello", "body": "Your order is ready" }
]

3. Understand APNs and the APNs key

APNs (Apple Push Notification service) is Apple's push service itself; every iPhone notification goes through it. To use it you need an APNs key, which proves the sender is allowed to push to that app.

I thought of it as an HTTPS certificate, which is close. The difference is that a browser checks an HTTPS certificate, while Apple checks the APNs key. The user's phone doesn't verify anything itself; it just trusts Apple. Answer yes to "Set up Push Notifications" during the build and Expo creates the key for you and keeps it in your Expo account.

4. Expo and EAS are not the same thing

  • Expo: the company and the open-source framework itself, including the SDK, the CLI, Expo Go and the free push service.
  • EAS (Expo Application Services): Expo's cloud services, such as Build, Submit and Update. The free plan has quotas.

Push belongs to Expo, not EAS Build, so sending notifications never uses build credits.

5. Compared with Kafka pub/sub

The idea is similar: a group of users is like a topic, users are like subscribers and a notification is like a message. But a few things differ:

Kafka Expo push
Who picks recipients Consumers subscribe themselves The backend picks them at send time
How it arrives Consumers pull Pushed all the way to the phone
Storage Messages can be re-read Not kept; Apple holds only the latest for an offline phone
Ordering Guaranteed within a partition Not guaranteed

So anything important should also live in your own database, with the push as a reminder.

Pitfalls

  • Adding the push package needs a new build: it has native code, so a JavaScript update isn't enough.
  • Don't say no during the build: if you want remote push, answer yes, or there's no APNs key and Expo can't reach Apple. Apps that only use local notifications don't need it.
  • Tokens die when users delete the app: Expo's receipts tell you, so clean them up now and then.
  • There's a per-second limit: 600 notifications a second per project; beyond that, queue and retry.

What improved

  • The two tokens: I used to think they were one thing; now I know the Expo token wraps Apple's device token.
  • APNs: not just a certificate, but Apple's own service, and Apple is the one that checks the key.
  • Expo and EAS: push belongs to Expo, is free and sits outside build quotas.
  • Phone to phone: phones never send directly; it's a relay from my backend to Expo, then Apple, then the phone.

Comments