All posts Mobile Development

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.

DT
Demir Taşdemir Mobile App & Web Developer
— min read

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)
}
Send it on every app launch too

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:

CauseWhat happens
Battery optimization / sleep modeThe notification is delayed or arrives in a batch
Manufacturer restrictionsSome brands aggressively kill background apps
Device off for a long timeThe notification expires and is dropped
User has turned notifications offIt 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
Share: LinkedIn X WhatsApp
DT

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.