The Part of Push Notifications Nobody Tells You About
Wiring up notifications takes twenty minutes; making them work correctly takes months. On the token lifecycle, silent failures, and getting from a notification to the right screen.
As the documentation presents it, setting up push notifications takes twenty minutes: add the library, drop in the key, send a test notification, done. The problem is that in a real app 80% of the work starts after those twenty minutes.
What follows is what I learned on the notification side of my apps — the things I never found collected in one place in the documentation.
1. The token is not permanent
This is the most basic misconception. People assume the device token is permanent: they fetch it once, send it to the server and forget about it. In reality the token changes in these situations:
- When the user deletes the app and reinstalls it
- When the app data is cleared
- When the device is restored from a backup
- During the system's own refresh cycle
When the token is refreshed, the record on the server goes stale and that user silently stops receiving notifications. There is no error either — the notification simply never goes out.
// Report the token to the server every time it is refreshed
FirebaseMessaging.getInstance().token.addOnSuccessListener { token ->
sunucuyaKaydet(token)
}
// And listen for the refresh event as well
override fun onNewToken(token: String) {
sunucuyaKaydet(token)
}
In case you miss the refresh event, sending the current token to the server on every app launch is cheap insurance. If it is unchanged on the server side, nothing happens.
2. Clean up dead tokens
When a user deletes the app, the token becomes invalid. The delivery service tells you so with an error code. If you don't catch that code and delete the record from your database, over time a large share of the notifications you send turns into junk traffic that reaches nobody.
Handling the delivery response matters far more than saying "sent it, done":
// Handle the errors in the delivery response
if (hata == "UNREGISTERED" || hata == "INVALID_ARGUMENT") {
tokenKaydiniSil(token) // this device no longer exists
}
3. Ask for permission at the right moment
On iOS, and on Android 13 and later, notification permission has to be requested explicitly. And once it is denied you cannot show the system dialog again — you are stuck sending the user off to settings.
That is why asking on the app's first launch is the worst strategy. The user doesn't even know what the app is for yet, denies it reflexively, and you lose that chance permanently.
The path I follow: first explain on my own screen why I would send notifications, and open the system dialog only if the user says yes. If they say "not now", I never open the system dialog — the permission stays available, and I can ask again later.
4. Sent is not the same as delivered
When the delivery service says "success", the notification has not been handed to the device; it has only been queued. There are layers in between that can stop it from arriving:
| Cause | What happens |
|---|---|
| Battery optimization / sleep mode | The notification is delayed or arrives in a batch |
| Manufacturer restrictions | Some brands aggressively kill background apps |
| Device off for a long time | The notification expires and is dropped |
| User has turned notifications off | It silently never appears |
This is why you should never trust a notification alone with critical information. A notification is a reminder layer; the information itself has to be visible inside the app as well.
5. Tapping a notification must open the right screen
This is the gap I see most often. The user taps a "your order has shipped" notification, the app opens on the home screen, and they have to go find the order themselves.
The right behavior is to go straight to the screen the notification's payload points at. What you have to watch out for here is that the app can be opened in two different states:
- Cold start: the app was closed when the notification was tapped. The notification data has to be read in the launch flow, and the routing has to happen after the home screen is ready.
- Warm start: the app was in the background. This time the launch flow doesn't run; a separate event fires instead.
If you don't handle the two cases separately, one of them works while the other silently leaves the user on the home screen. Always test both: once with the app fully closed, once with it in the background.
6. Think about the way back
When a user lands deep inside the app from a notification and presses back, what should happen? Dropping them out of the app is usually the wrong behavior. The right thing is to build a sensible navigation stack underneath that screen — pressing back should take them to the home screen.
7. Frequency matters more than content
The most common reason a notification drives users away is not that the content is bad, but that it arrives too often. Once notification permission is turned off, winning it back is nearly impossible.
- Let users turn notification types off individually — don't force them to switch everything off at once.
- Don't send during the night; schedule around the user's local time.
- Don't send back-to-back notifications about the same thing; group them.
A push notification is the most fragile permission a user grants you. Abuse it once and you don't get it back.
- Push notifications
- FCM
- Token management
- Deep linking
- Permissions
Demir Taşdemir
Mobile App & Web Developer
I have been building software since 2018. I have published 11 apps on the App Store and Google Play; right now I am working on 6 mobile apps, 1 e-commerce platform and 1 desktop game.
A developer who doesn't skip the details
The difference between a feature that works and a feature that works reliably lives in details like these.