At 14:00 a retailer marks an order ready for collection. At 14:01 its server receives a successful response from the push provider. At 15:20 the customer opens the app and finds the order waiting. They never saw the notification.
Was the message delivered? The provider accepted it. The operating system may have delayed it. The user may have disabled alerts, Focus may have suppressed presentation or the device token may have been stale.
“Sent” is not one state.
Draw the chain
Apple documents four components in remote delivery: the provider server, APNs, the user's device and the app. It also states that “delivery isn't guaranteed”.
For one notification, the path may be:
order_ready event
→ eligibility and preference check
→ template render
→ provider request accepted
→ platform delivery decision
→ device presentation
→ user tap
→ app route
→ fresh authorised order stateInstrument the transitions you control and name the others honestly. Provider acceptance is not device delivery. Device delivery is not presentation. Presentation is not a useful action.
Send an event reference, not the product state
A notification payload should contain enough to route and deduplicate, not a portable copy of sensitive or rapidly changing truth.
{
"notificationId": "ntf_01J…",
"type": "ORDER_READY",
"orderId": "ord_01J…",
"route": "/orders/ord_01J…"
}When the user opens it, the app retrieves the latest authorised order. The collection time may have changed, the order may have been collected on another device or the session may have expired. The deep link should resolve those states instead of assuming the payload is current.
Avoid placing personal or confidential content on a lock screen by default. Notification preferences should be granular enough for people to distinguish operational messages from marketing.
Make sending idempotent
Queues retry and providers time out. Give the notification intent a stable ID before the first send. If a worker receives the same event twice, it should return or update the same send record rather than create another user-visible message.
The app also needs deduplication. Two platform deliveries for the same notificationId should not create two inbox entries or repeat an action. A notification tap navigates to a state; it should not execute an irreversible command hidden inside the route.
Use provider collapse or replacement features only for messages where the newest value genuinely supersedes the old one. Apple notes that APNs may coalesce notifications for the same app when immediate delivery is not possible. That behaviour suits “latest score” better than “each payment failed”.
Ask for permission after explaining the value
The first-launch permission prompt is easy to implement and expensive to waste. Ask when the user has encountered a reason to say yes:
- after choosing delivery updates;
- while enabling price alerts;
- when saving a live journey;
- after selecting a reminder.
Explain the categories and let the user change them later. A technically reliable notification programme that people disable is not reliable in product terms.
Firebase Cloud Messaging distinguishes notification messages, which the platform can display, from data messages, whose behaviour the app controls. Choose based on the product state and platform constraints, not on a desire to funnel every update through one payload type.
Test the destination, not only the banner
Build a device matrix that includes:
- foreground, background and terminated app states;
- old and current app versions;
- revoked permission;
- rotated or invalid tokens;
- signed-out and switched accounts;
- delayed delivery;
- the target entity changed or deleted;
- a deep link opened from a cold start.
Apple provides a Push Notification Console and delivery logs for integration testing; Firebase offers delivery data and export options. Combine provider evidence with in-app events and the originating business event to understand the whole funnel.
This systems view is part of our mobile engineering, from transport experiences such as Virgin Trains Ticketing to products where one useful alert must land in the right account and current state.
The goal is not to guarantee a channel the platforms explicitly do not guarantee. It is to make every controlled step dependable and every uncontrolled step recoverable.
Sources
Filed under
- Push notifications
- Mobile infrastructure
- Reliability
- Messaging
