Skip to main content

Push Notification Failures on Android and iOS

Trace mobile push notification problems through permissions, APNs and FCM registration, account mapping, message expiry and deep-link handling.

R
Written by Reiko

Provider acceptance and an alert displayed on a phone are separate events. A separate message appears twice, and tapping it opens the wrong account. These are separate failures along a delivery pipeline. The investigation needs to follow one message from the application server to the device and finally to the action the user sees.

Map the notification pipeline before testing delivery

Record the business event, intended recipient, registered installation, provider request and client handling. Distinguish a scheduled event from a successfully submitted push request. Distinguish provider acceptance from device receipt and visible presentation.

Stage

Useful evidence

What it does not prove

Event created

Event ID and recipient selection

A send request reached the provider

Provider accepted request

Provider response and message identifier

The notification appeared on screen

Client processed message

Supported client telemetry

The user read the message

User opened notification

Open event and validated destination

The requested business action completed

Not every message type or platform exposes the same receipt information. Label unavailable stages as unknown instead of counting acceptance as a delivered notification. This prevents an apparently excellent delivery rate from hiding permission or presentation problems.

Check permission independently of registration

Android 13, API level 33, introduced the POST_NOTIFICATIONS runtime permission for non-exempt notifications. The target SDK and installation history affect aspects of the permission flow. Test the actual supported combinations rather than assuming a successful send proves the app can display an alert.

On iOS, requesting permission for visible notifications and registering with APNs serve different purposes. Inspect the current authorisation state and the presentation options used by the app. A token is a routing identifier, not evidence that the user has agreed to every kind of alert.

Ask in a context that explains the benefit, such as a player choosing a match reminder. If permission is denied, preserve normal app navigation and show an appropriate settings path where needed. Repeating a prompt or breaking an unrelated screen does not repair delivery.

Keep registration fresh and environment-specific

Apple describes an APNs device token as specific to the app and device. Obtain the current token through registration and forward it securely to the provider backend. Do not assume a locally remembered token remains valid across installation and system changes.

The backend may need several registrations for one account because a player can use multiple devices. Include the app, platform and environment in the registration model. A development token and production route must not be mixed simply because the account is the same.

Firebase documents Android FCM registrations becoming expired after 270 days of inactivity. That is not a universal lifetime for all push systems; its documentation explicitly distinguishes iOS, where APNs does not have that same inactivity-based rule. Remove invalid registrations according to the provider's documented responses and maintain a freshness policy suitable for the product.

A generic invalid-argument response can also indicate a malformed payload. Check its documented meaning before deleting registrations in bulk. A payload bug should not erase the server's list of otherwise reachable devices.

Prevent messages from following the wrong account

Installation registration and account association have different lifetimes. After sign-out, an old registration must not continue receiving private information intended for the previous profile. Define what is detached, revoked or retained for account-independent messages.

Consider a shared phone where player A signs out and player B signs in. A queued notification for A can arrive later. Keep sensitive details out of the payload where possible, verify the active account when handling the message and fetch protected content through an authorised request.

Do not treat a notification payload as permission to read a message, grant a reward or open another player's profile data. The destination service still needs to enforce access. A stale alert should lead to a clear unavailable or wrong-account state rather than silently changing profiles.

Choose expiry and collapse behaviour for the event

A reminder that a match starts shortly has little value after the match ends. Set the supported expiry controls according to the event's useful lifetime, and recheck the underlying state when the app opens. Push is not an exact alarm or a guaranteed scheduling mechanism.

Collapse or replacement behaviour can be useful for the newest status of one object. It is inappropriate when every distinct event must remain independently visible. Use the provider's exact semantics and test them on supported clients; a replacement key is not a transaction ledger.

If a backend job retries after losing the provider response, the user may receive a duplicate. Track the logical event separately from each send attempt. Where appropriate, use client-side deduplication with a bounded history, while retaining durable server state for any important action.

Handle foreground, background and notification taps

The app's state changes who presents or processes a message. Test foreground handling, background delivery and opening after the process has been absent. Avoid simultaneously showing a local alert and a provider-managed alert for the same message unless that is deliberate.

A deep link may arrive before authentication, navigation or content loading is ready. Retain a validated pending destination and open it after the required state is established. Define what happens if the user cancels sign-in or the event has expired.

Allowlist supported routes and parse their parameters defensively. A notification should not become a general mechanism for opening arbitrary internal screens or performing privileged actions. Opening an inbox entry is different from approving a transaction.

Keep important events available inside the app

A push should draw attention to durable server state where the event requires reliable follow-up. Store a match invitation, account notice or support reply in an authenticated inbox, then use the notification as an optional pointer to it. The user can discover the event on their next normal visit even if the alert was suppressed.

Reconcile unread state when opening the inbox rather than incrementing a permanent counter for every received push. Duplicate, collapsed and delayed messages can otherwise corrupt the badge. If an invitation expires, preserve an explanation of its status instead of showing an actionable button that can no longer work.

Test an account that receives no push at all. The relevant event should still appear through the normal authenticated fetch, subject to the product's retention and access rules. This makes missed notifications inconvenient rather than a source of lost business state.

Calculate a delivery funnel without changing denominators

Suppose a test campaign targets 1,000 installations, the provider accepts 950 requests and 760 accepted messages have a supported receipt signal. Acceptance is 95% of targeted installations. Observed receipt is 80% of accepted messages and 76% of targeted installations.

Those percentages are different measurements, not competing versions of one delivery rate. Missing receipt telemetry does not necessarily mean the message was not delivered. Segment by platform, message type, app state and permission status before drawing conclusions.

Do not infer a reading rate from notification opens alone. Users may see an alert without tapping it, open the app another way or receive a collapsed replacement. Choose a measurement tied to the actual product question.

Use a small, controlled diagnostic campaign

  1. Register known test devices and verify the intended environment.

  2. Record permission and account state before sending.

  3. Send one uniquely identified message with a known destination.

  4. Repeat in foreground, background and after a network interruption.

  5. Change accounts and verify that private routing is detached.

  6. Repeat after app update and registration refresh.

Keep tokens and user identifiers out of public debugging screenshots. Compare the server's routing record with the device's current state, then repair the failing stage. Increasing send volume rarely fixes an incorrect token, denied permission or navigation bug.

Did this answer your question?