Push notifications
How push notifications reach phones and browsers through APNs, FCM and Web Push, device token management, fan-out to millions, user preferences and quiet hours, deduplication, rate limits, collapsing, and measuring delivery.
Reading is half of it. See this used in a real interview: walk through Design a Notification System →
Push notifications look like one API call: "send this to that user". In practice they go through platform gateways you do not control, to devices whose tokens expire, for users who have preferences, quiet hours and a low tolerance for spam. And sometimes you need to send one to 100 million people in a few minutes. This guide covers the design behind a reliable notification pipeline.
How push reaches a device
Apps cannot keep their own connections open in the background (it would drain the battery), so the operating system keeps one connection to the platform’s push service:
- APNs (Apple Push Notification service) for iOS and macOS.
- FCM (Firebase Cloud Messaging) for Android and also usable for iOS and web.
- Web Push (VAPID) for browsers.
Your server sends the message to the platform service with the device’s push token; the platform delivers it when the device is reachable. Delivery is best effort: the platform may delay, collapse or drop messages, especially for devices that are offline or in low-power modes.
Device tokens
- The app registers on install and launch, obtains a token, and sends it to your backend with the user id, platform, app version and locale.
- A user has many devices; store a token per device.
- Tokens change (reinstalls, restores) and expire; the platforms tell you when a token is invalid (APNs returns
410 Unregistered, FCM returnsUNREGISTERED). Delete those tokens immediately, or you will keep paying to send into the void. - Log the user out of push when they log out of the app.
The pipeline
- Event from a product service ("order shipped", "new message") published to a queue.
- Notification service decides whether and how to notify: looks up user preferences, quiet hours, frequency caps, and chooses channels (push, email, SMS, in-app).
- Rendering with templates and the user’s language.
- Per-channel senders call APNs, FCM, an email provider or an SMS provider, with retries and rate limits.
- Feedback: delivery receipts, invalid tokens, opens and unsubscribes flow back.
Keep the stages separate with queues so a slow provider does not block others. See Design a Notification System and background jobs.
Priority and isolation
A password reset or a 2FA code must not wait behind a marketing campaign to 50 million users. Use separate queues and worker pools by priority (transactional, social, marketing), so the bulk send cannot starve the urgent ones.
Fan-out to millions
Sending a breaking-news alert to 100 M devices:
- Do not load 100 M tokens in one process. Split the audience into segments or shards and enqueue batch jobs.
- Respect platform throughput and use batch APIs where available; spread sends over minutes if the content allows.
- Topics (FCM) let the platform do the fan-out for broadcast messages; you publish once.
- Expect a thundering herd on your own servers: when 100 M people tap the notification at once, the app opens and calls your API. Pre-scale, cache the target content, or stagger sends. See autoscaling.
Deduplication, collapsing and frequency
- Idempotency: assign each notification an id; retries in your pipeline must not send twice. See distributed transactions and idempotency.
- Collapse keys replace an older pending notification with a newer one (score updates, "5 new messages" instead of five pushes).
- Batching and digests: "Alex and 12 others liked your photo" beats 13 pushes.
- Frequency caps per user and category, and quiet hours in the user’s time zone, with urgent categories exempt.
Users who get too many notifications turn them off entirely, which is far more costly than one missed push.
Preferences and consent
Store per-user, per-category, per-channel preferences, check them at send time (not when the campaign was created), and honour unsubscribes immediately. Marketing messages need consent under many laws; transactional ones (receipts, security alerts) are usually separate.
Silent pushes and in-app
- Data-only (silent) pushes wake the app to sync content without showing anything; platforms throttle them heavily, so never rely on them for correctness.
- An in-app inbox stores notifications server-side so the user sees everything when they open the app, even if pushes were dropped. For chat, the message store, not the push, is the source of truth; the push is only a hint to connect. See Design WhatsApp.
Measuring it
Track per channel and category: sent, accepted by the platform, delivered (where reported), opened, invalid-token rate, unsubscribe rate after a notification, and end-to-end latency from event to device for transactional messages. A drop in delivery for one platform version is often the first sign of a token or certificate problem.
Checklist
- Tokens per device, refreshed and deleted when invalid.
- A queued pipeline: decide, render, send, feedback.
- Priority isolation between transactional and bulk sends.
- Sharded fan-out and protection against the open-rate herd.
- Idempotent sends, collapse keys, digests, frequency caps, quiet hours.
- Preferences and consent checked at send time.
- An in-app inbox as the source of truth; delivery metrics per platform.