Firebase Cloud Messaging: How Push Notifications Actually Work
FCM is Google's free service for sending push notifications. Here is the whole journey, from your server to the phone in someone's hand.
9 min read · updated August 5, 2026
Firebase Cloud Messaging — FCM for short — is a free Google service that delivers messages to phones and browsers. When an app you have not opened in three days buzzes to tell you something, a service like this carried that message.
It is free with no message limit. That is unusual enough to state plainly up front, because most questions about FCM pricing come from people expecting a bill.
Why apps cannot just message you directly
Here is the problem FCM solves. Your app is closed. It is not running, not listening, not using battery. Your server has news for it. How does it get through?
It cannot, directly. A closed app is genuinely closed. If every app kept a connection open just in case, your battery would be gone by lunchtime.
The journey of one notification
Follow a single message from your server to a phone. Five steps:
- 1
The app registers
On first launch the app asks FCM for a registration token — a long unique string identifying this app on this specific device. Not the user. Not the phone. This install.
- 2
The app sends the token to you
Your app posts that token to your own server, which stores it against the user. Now you know where to send things.
- 3
Your server asks FCM to deliver
You call the FCM API with the token and the message. You never contact the phone yourself.
- 4
FCM routes it
On Android, FCM delivers over Google's connection. On iOS, FCM hands the message to APNs — Apple Push Notification service — because Apple only lets Apple push to iPhones.
- 5
The phone wakes the app
The operating system shows the notification, or wakes your app to handle it.
Step four is the one that surprises people. On iOS, FCM does not deliver your notification. Apple does. FCM is a middleman that speaks to APNs on your behalf, which is why iOS push requires an extra key from Apple.
Notification messages vs data messages
FCM sends two kinds of message, and picking the wrong one causes a lot of confusion.
| Notification message | Data message | |
|---|---|---|
| Who displays it | The operating system, automatically | Your code |
| App closed | Shows anyway | Your handler may not run |
| Contains | Title, body, icon | Whatever key-value pairs you want |
| Good for | "You have a new message" | Syncing data quietly in the background |
A common bug: sending a notification message and wondering why your custom handler code never runs when the app is closed. The system displayed it without asking your app. If you need your code to run, send a data message.
Sending to many people at once
Storing a million tokens and looping through them is not the answer. FCM gives you two better tools.
- Topics. Devices subscribe to a name like
weather-london. You send one message to the topic and FCM fans it out. The device decides what it cares about, so you do not have to keep lists. - Device groups. One person, several devices. Send once, reach the phone and the tablet.
Why your notification did not arrive
This is the most-searched FCM problem, so here are the real causes in the order they are usually to blame.
- The token expired. Tokens change — on reinstall, on restore to a new phone, sometimes on app update. Sending to a dead token fails silently. Refresh tokens on every launch and delete the ones FCM rejects.
- iOS is missing its APNs key. No key uploaded to Firebase means Apple never gets the message. Android keeps working, which is why this bug is often reported as "push works on Android but not iPhone".
- The user denied permission. On iOS and on Android 13 and later, notification permission is a prompt the user can refuse. Refused means nothing arrives, forever, until they change it in Settings.
- Battery optimisation. Some Android manufacturers aggressively kill background apps. The message reaches the phone; the app never wakes.
- You sent a data-only message with low priority. The system is entitled to hold it. Set high priority if it is time-sensitive.
What it looks like in code
Getting a token, on the web:
import { getMessaging, getToken } from "firebase/messaging";
const messaging = getMessaging();
const token = await getToken(messaging, {
vapidKey: "YOUR_PUBLIC_VAPID_KEY",
});
// Send this to your own server and store it against the user.
await fetch("/api/save-token", {
method: "POST",
body: JSON.stringify({ token }),
});Sending one, from a server using the Admin SDK:
import { getMessaging } from "firebase-admin/messaging";
await getMessaging().send({
token: usersStoredToken,
notification: {
title: "Your order shipped",
body: "Arriving Thursday",
},
});That is the whole API surface for a basic push. The complexity in FCM is almost never the sending — it is the tokens and the platform setup.
Platform setup, briefly
| Platform | What you need beyond the SDK |
|---|---|
| Android | google-services.json in the app module. Notification permission prompt on Android 13+. |
| iOS | An APNs authentication key (a .p8 file) uploaded to Firebase, plus the Push Notifications capability in Xcode. |
| Web | A service worker file and a VAPID key. |
| Flutter | The firebase_messaging package, plus the native setup for each platform above. |
| React Native | @react-native-firebase/messaging, plus the same native setup. |
There is no shortcut around the native setup. Cross-platform frameworks wrap the API, not the platform requirements — Apple still wants its key.
What FCM costs
Nothing. There is no per-message charge and no monthly cap on notifications.
You can still generate a bill around it. If a notification triggers a Cloud Function, or your send logic reads Firestore for every recipient, those services bill normally. The messaging is free; what you do either side of it is not.
Frequently asked questions
- Is Firebase Cloud Messaging free?
- Yes. There is no charge per message and no cap on how many you send. Costs only appear if sending triggers other paid services, such as Cloud Functions or heavy Firestore reads.
- What is the difference between FCM and APNs?
- APNs is Apple's own push service and is the only way to reach an iPhone. FCM is Google's service, and on iOS it forwards your message to APNs. You use FCM so you can write one integration for both platforms rather than two.
- Why do push notifications work on Android but not iOS?
- Almost always a missing or expired APNs authentication key in your Firebase project settings. Android does not need it, so the Android path keeps working while iOS silently fails.
- What is an FCM token?
- A unique string identifying one installation of your app on one device. It is not a user ID — reinstalling the app produces a new token, and the old one stops working.
- How do I send a notification to all my users?
- Subscribe devices to a topic and send one message to that topic. FCM handles the fan-out. Looping through stored tokens works but is slower and harder to keep accurate.
- Is FCM the same as GCM?
- FCM replaced Google Cloud Messaging. GCM was shut down, and its APIs no longer work. Any tutorial that mentions GCM endpoints is out of date.