Testing push notifications: a complete checklist

Sending a push is easy. Delivering the right one, to the right state, at the right time — that is where the bugs live. Here is the checklist my team runs.

Push notification testing looks simple from the outside: send a message, see it arrive. In practice it is one of the most state-dependent features in a mobile app. Delivery depends on permission state, app lifecycle, device power mode, token freshness, and two platforms with different opinions about all of it. Here is the checklist my team works through before we trust a notification feature.

Push notification testing starts with permissions

Map every permission state and test each one: never asked, granted, denied, and revoked later from system settings. On iOS, add provisional authorization, where notifications arrive quietly without any prompt. On Android 13 and later, notifications require a runtime permission just like the camera — older test devices will mislead you here. Also verify the app behaves sanely when a user denies the prompt and then triggers a flow that expects notifications, like enabling order updates.

Foreground, background, killed

The same notification behaves differently in each app state, so test all three. In the foreground: does the app show an in-app banner, or suppress the notification and update the UI directly? In the background: does tapping resume the existing session with correct state? Killed is the interesting one. On Android, force-stopping an app from settings blocks message delivery entirely until the next manual launch — that is OS behavior, not a bug, and you need to know the difference before filing it.

The tap is a deep link

Every actionable notification carries a payload that routes somewhere. Test the payload like an API contract: correct target with valid data, missing fields, extra fields, and a target that no longer exists. Tapping a notification about a deleted item should land on a graceful fallback, not a blank screen or a crash. Repeat the tap with the app killed, backgrounded, and already sitting on the target screen — the last case loves to stack duplicate screens.

Token refresh and opt-out

Device tokens rotate on reinstall, on restore from backup, and occasionally after OS updates. Reinstall the app and confirm a fresh token registers while the old one stops receiving. Then test every opt-out path: the in-app toggle, per-category unsubscribes, and OS-level disabling. Opt-out bugs are trust killers — a user who disabled marketing pushes and still receives one will uninstall, and they will be right to.

Timing, quiet hours, and platform quirks

If the product supports scheduled sends or quiet hours, test across time zones and around daylight saving transitions, with the device clock and the account setting deliberately mismatched. On Android, Doze mode delays normal-priority messages, sometimes by a long while; high-priority messages punch through, so verify each notification type is assigned the right priority and the right channel. On iOS, check how notifications group and stack, and what the lock screen shows when previews are turned off.

Delivery is not verifiable from the app alone. Pair every test with the sender side — a test campaign or a direct call to the push API from Postman — so you can tell "never sent" apart from "sent and swallowed." Half of my push bug reports would have blamed the wrong layer without the server logs to check against.

Push notifications sit at the intersection of OS policy, network behavior, and user consent, which is why one-off manual checks keep missing things. Treat this checklist as a matrix — permission state times app state times payload type — and walk it deliberately whenever the notification code or the sending service changes. It is tedious exactly once; after that it is a routine that finds the bugs your users would otherwise find for you, at midnight, in the wrong time zone.