You don’t send a push notification directly to a phone. You send it to Apple or Google, and they deliver it for you. That indirection has consequences most backend engineers don’t think about until something breaks.

APNs and FCM#

Apple Push Notification Service (APNs) handles iOS. Firebase Cloud Messaging (FCM) handles Android (and can handle iOS too). Your server maintains a persistent HTTP/2 connection to these gateways and submits payloads. The gateway handles the actual delivery to the device, retries if the device is offline, and tells you when a token is no longer valid.

Device tokens are the key concept. When a user installs your app, the OS registers with APNs/FCM and gives back a token. Your app sends that token to your server. The token is how you address that specific device. Tokens rotate when the user reinstalls the app, restores from backup, or iOS decides to refresh them. Stale tokens bounce back with an error code that means “this device is gone, stop sending here.”

graph TD A[Your Server] --> B[APNs / FCM Gateway] B --> C{Device Online?} C -->|Yes| D[Deliver to Device] C -->|No| E[Hold in Gateway Queue] E --> F{Device Comes Online} F --> D B --> G{Token Valid?} G -->|No| H[Return Invalid Token Error] H --> I[Remove Token from DB] style A fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style B fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style C fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style D fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style E fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style F fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style G fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style H fill:#000000,stroke:#ff0000,stroke-width:2px,color:#fff style I fill:#000000,stroke:#ff0000,stroke-width:2px,color:#fff

At Salesforce#

Salesforce mobile sends a lot of push notifications: approval requests, task assignments, chatter mentions. For a while, our token table had no cleanup. We were attempting delivery to tokens from users who had uninstalled the app two years ago. Around 30% of our outbound pushes were bouncing with invalid token errors. Cleaning up the token table and processing bounce-backs properly dropped that to under 3%. Not just for efficiency, it matters because gateways will throttle senders with high bounce rates.

What I’m Learning#

Silent pushes (content-available: 1 on APNs) let you wake the app in the background to refresh data without showing a notification. Useful for keeping offline caches warm, but iOS limits how often it honors them.

Have you dealt with token management at scale, or just assumed the push would get there?