Push Notifications — FCM and Web Push
Push Notifications — FCM and Web Push
To deliver messages on mobile or web while the app is closed, the push channels provided by the OS or the browser must be traversed. iOS has APNs, Android has FCM, and the web has the Web Push standard.
1. About FCM
FCM (Firebase Cloud Messaging) is Google's push messaging service. It is the successor to GCM (Google Cloud Messaging, 2012). The brand was unified to FCM in 2016, and the GCM API was retired in stages (2018 to 2024). The currently recommended API is HTTP v1 (the legacy server key API is deprecated).
FCM bundles the following channels.
- Android — its own channel.
- iOS — internally delivered via APNs.
- Web — runs on top of standard Web Push.
2. APNs and Web Push
APNs (Apple Push Notification service) — Apple's own channel (introduced in 2009). Delivers messages to iOS, iPadOS, macOS, watchOS, and tvOS. Authentication is token-based (JWT) or certificate-based.
Web Push — browser push standardized by W3C and IETF. RFC 8030 (HTTP Web Push, 2016), RFC 8291 (message encryption, 2017), RFC 8292 (VAPID, 2017). VAPID is the mechanism by which the sender proves its identity to the push service. Chrome, Firefox, Edge, and Safari support it (Safari from 16.4 / 2023 on macOS and iOS 16.4+).
3. Token lifecycle
① Request the client asks the user for push permission
② Issue OS or browser issues a token (or subscription). Unique per app and device.
③ Deliver the client registers the token with its backend
④ Use the backend submits the token plus message payload to the push service
⑤ Refresh OS may invalidate and reissue tokens at will
⑥ Expire when the user disables permission or removes the app, failures pile up even if the token is alive
Tokens do not last forever. A refresh and cleanup flow is needed.
4. Message types (FCM-based)
| Type | Behavior |
|---|---|
| notification | Auto-displayed in the system tray. Handled by the OS when the app is backgrounded. |
| data | Payload only. The app handles it directly. Background processing limits vary by OS. |
| combined (notification + data) | Both. Background goes to OS, foreground to the app. |
iOS background data-only messages are subject to additional flags like content-available: 1 and OS processing priority assumptions. Reliability is often reported as not guaranteed.
5. Payload and firebase-admin
FCM HTTP v1 payload example:
{
"message": {
"token": "<device_token>",
"notification": {
"title": "새 메시지",
"body": "확인해 주세요"
},
"data": {
"type": "chat",
"chat_id": "1234"
},
"android": { "priority": "high" },
"apns": {
"payload": {
"aps": { "sound": "default" }
}
}
}
}
Node, Python, Java, Go, and .NET SDKs are available.
import { initializeApp, cert } from 'firebase-admin/app';
import { getMessaging } from 'firebase-admin/messaging';
initializeApp({ credential: cert(serviceAccountJson) });
await getMessaging().send({
token,
notification: { title, body },
data: { type: 'chat', chat_id },
});
The service account JSON key is a secret. Manage it via environment variables or a secret manager. The SDK abstracts OAuth2 token refresh and HTTP v1 calls.
6. Self-hosted Web Push server
Generate VAPID keys (public/private pair), and the client receives a subscription via pushManager.subscribe(...). The server calls the push service (Firefox autopush, Chrome FCM endpoint) directly using libraries like web-push (Node) or pywebpush (Python). Payloads are encrypted with ECE (RFC 8188).
This path works without Firebase enrollment. iOS Web Push (16.4+) follows the same standard.
7. Comparison with OneSignal
OneSignal is a managed service that bundles push, email, and SMS (2014). It abstracts FCM, APNs, and Web Push under one SDK. Analytics, segmentation, and A/B are often cited as strengths. Limits are that user data lives externally and free tier caps.
| Item | FCM (direct) | OneSignal | Self-hosted Web Push |
|---|---|---|---|
| Mobile (iOS+Android) | possible (firebase-admin) | possible | iOS only on 16.4+ web |
| Web | possible (FCM JS SDK) | possible | possible (VAPID) |
| Analytics, segmentation | basic only | strong | implement yourself |
| Data ownership | through Google infra | through OneSignal | own + push service |
| Cost | usage-based (Google) | tiered | very low |
8. Token cleanup and topics
The server reads send results and cleans up failed tokens.
- FCM: errors like
messaging/registration-token-not-registered→ delete the token row. - Web Push:
410 Goneor404 Not Found→ delete the subscription.
FCM provides a topic subscription model (/topics/news). One call sends to all subscribers of the same topic. However, with many users, response delays on topics get reported. When precise distribution matters, batch and multicast with explicit token bundles is more common.
9. Common pitfalls
Using the legacy server key API — confirm migration to HTTP v1. The old GCM/FCM legacy API is a retired place.
Reliability of iOS data-only — background data-only messages are shaken by OS processing policies. Include a notification payload too when display is required.
Missing service worker — Web Push requires a registered service worker to receive messages. A service worker is needed even if it is not a PWA.
Lost VAPID keys — losing the keys for self-hosted Web Push invalidates existing subscriptions.
Notifications after app kill — some Android OEMs block background processing for force-killed apps, which may delay or drop notifications.
Payload size limits — both APNs and FCM have payload size limits (about 4KB). For larger data, send only a token and let the client call a separate API.
Timezone assumptions — naive sending that ignores the user's timezone results in midnight notifications.
Closing thoughts
Push hits its hardest step at user consent. Whether the first notification after consent feels valuable decides the opt-out rate. Late-night notifications and excessive frequency are places where permission slams shut at once.
Next
- image-pipeline
- backup-restore
References: FCM official docs, FCM HTTP v1, APNs official, RFC 8030 — HTTP Web Push, web-push npm, MDN Push API.