How does the Apple Push Notification service deliver a push: tokens, priority, collapse, expiry, and what can go wrong?
Predict first
A device was offline for an hour while a server sent 50 live-score pushes with the same collapse id and then reconnected. How many notifications does it receive?
// A: all 50, in order
// B: one, the latest, because collapsed pushes replace the undelivered older ones
// C: none, because APNs discards offline pushes
- A
- B
- C
Mental model. APNs is a postal sorting centre. You hand it a letter with an expiry date and a “replace the previous letter” tag; it forwards it when the recipient’s address is reachable, and keeps only the latest if the recipient is away. It never tells you the letter was read.
A remote notification travels provider (your server) → APNs → device → app. At launch the app calls registerForRemoteNotifications(); the system obtains a device token from APNs and returns it in application(_:didRegisterForRemoteNotificationsWithDeviceToken:); the app uploads it to your server along with the user and environment (sandbox or production tokens are different). The server authenticates to APNs with a token-based key (a .p8 signing key, the modern way: one key per team, no yearly renewal) or with certificates, and sends an HTTP/2 request to /3/device/<token> with headers: apns-topic (the bundle id, with suffixes for push types such as .voip), apns-push-type (alert, background, voip, liveactivity…), apns-priority (10 delivers immediately and may wake the screen; 5 is power-aware and may be delayed, required for silent background pushes), apns-expiration (how long APNs stores a push for an offline device; 0 means try once and discard) and apns-collapse-id (a newer push with the same id replaces the older undelivered one, so a device that was offline gets only the latest score update, not fifty).
The guarantees are weak by design. APNs is best effort: it holds only a limited number of undelivered pushes for an offline device (so older ones can be discarded), replaces an undelivered push that has the same collapse id, may drop pushes under load, and does not tell you whether the user saw it (a 200 means APNs accepted it). Silent pushes (content-available with background type) are throttled by the system (a few per hour), not delivered to force-quit apps (the user swiping the app away in the switcher stops background delivery until they launch it again, though visible alerts still arrive), and must not be relied on for correctness: use them as a hint to sync, with the app also syncing at launch. Common failures: a token from the wrong environment (BadDeviceToken), an expired or revoked token (410 Unregistered: delete it server-side, and re-register on each launch because tokens can change), a payload over the 4 KB limit, the wrong topic or key, a Focus mode or Low Power Mode hiding or delaying it, and notification permission being off. For rich content use a mutable-content push with a notification service extension (which has about 30 seconds to modify it). Design: send identifiers, not secrets, in payloads (the content passes through Apple), make handling idempotent, put the real data behind an authenticated fetch, and use collapse ids and appropriate priorities to limit noise. The background-delivery rules and silent-push limits are also covered in the platform topic.
APNs keeps one undelivered notification per collapse id, so the device gets only the most recent update.
Common traps
- Using a production device token against the sandbox endpoint, or the reverse. APNs answers
BadDeviceToken; keep the environment with each token. - Relying on silent pushes for correctness. They are throttled and not delivered to force-quit apps; also sync at launch and on foreground.
They might follow up with
- What does
apns-collapse-iddo? A newer push with the same id replaces an undelivered older one. - What does a 410 response mean? The token is no longer valid; remove it from your server.
Related questions
- 17.1.1 How do local and remote notifications work with UserNotifications: authorization, triggers, categories, and…
- 17.7.1 How do you approach an unfamiliar Apple framework: what do you check before you write code, and how do you…
- 6.5.2 What do the audio, location, VoIP and remote-notification background modes allow, and what is the catch?
← How do local and remote notifications work with UserNotifications…