Push notifications via APNs (Apple Push Notification service) remain the only reliable way to wake an iOS app in the background and deliver real-time messages. The basics haven't changed in years - register for a token, send a payload from your server through APNs, handle the notification on device - but the auth model, payload format, and background-delivery rules have all evolved. This guide covers the production-ready APNs patterns for 2026.
Token registration and the p8 auth key
The first job of any push-enabled iOS app is to get a device token from APNs and send it to your server.
The flow on the iOS side: in AppDelegate.application(_:didFinishLaunchingWithOptions:), call UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) - this prompts the user. If granted, call UIApplication.shared.registerForRemoteNotifications() on the main thread.
iOS then calls AppDelegate.application(_:didRegisterForRemoteNotificationsWithDeviceToken:) with the device token as Data. Convert it to a hex string and POST it to your server endpoint, which stores it alongside the user record. Re-register on each app launch to handle token rotation - APNs occasionally rotates tokens for security reasons.
Server-side auth: p8 keys are now standard. Apple supports two server-side auth methods for APNs: legacy p12 certificates (renewed yearly, scoped to a specific app) and modern p8 auth keys (never expire, scoped to your team, sign JWTs). For new projects, always use p8.
Get a p8 key: App Store Connect - Users and Access - Keys - APNs - create a new key. Apple gives you the key once (downloadable as a .p8 file). Note the Key ID. Note your Team ID. Note the bundle ID of the target app.
Server-side, sign a JWT with the p8 key (using ES256 algorithm), include the Key ID in the header and the Team ID as the issuer claim, and send the JWT as the authorization: bearer <jwt> header on every APNs request. The JWT is good for up to 1 hour - refresh before expiry. Modern push libraries (apns2 for Python, node-apn for Node) handle this automatically.
Payload structure, silent pushes, and background delivery
Standard payload. The APNs payload is JSON. The required field is aps, which contains the alert (with title and body), badge count, and sound. Custom data outside aps is passed to your app and can drive deep-linking - for example a custom_data key with screen and date fields that your notification handler reads to open the right screen at the right state.
Silent pushes (content-available). A silent push wakes your app in the background without showing the user a notification. Useful for refreshing data, syncing state, or triggering a background fetch. The key field is content-available: 1 with no alert/badge/sound. Required entitlement: UIBackgroundModes array must include remote-notification. Without it, silent pushes are silently dropped.
Silent push delivery is rate-limited by Apple - expect 2-3 deliveries per hour per device for typical apps, with bursts allowed. Apple throttles aggressive silent push usage to protect battery. Don't rely on silent pushes for real-time data; use them for cache invalidation and background sync.
Receiving and handling. When a notification arrives, iOS calls your AppDelegate's didReceiveRemoteNotification. For SwiftUI apps, prefer the modern UNUserNotificationCenterDelegate protocol with two methods: willPresent (called when notification arrives while app is foregrounded, return desired presentation options) and didReceive response (called when user taps the notification, route to the appropriate screen based on the payload).
For deep linking from a notification tap, read response.notification.request.content.userInfo to get the custom data, then call into your Router to navigate to the appropriate destination. The same Router pattern used for in-app navigation works cleanly here.
Quick comparison
| Option | Best for | Cost / effort | Notes |
|---|---|---|---|
| p8 key | Server auth | Never expires | ES256 JWT signed |
| Token registration | Per device | Send to server | Refresh on app launch |
| Standard payload | Visible push | alert/badge/sound | + custom data |
| Silent push | Background wake | content-available | remote-notification entitlement |
Common pitfalls and how to avoid them
Across every domain this article touches, the same shape of mistake recurs. Practitioners new to the field overweight the most visible piece of the system — the screenshot, the paywall, the exam question, the headline price — and underweight the underlying constraint that actually determines outcomes.
The five most common failure modes:
- Optimising for the demo, not the durability. A working demo in a controlled environment proves nothing about reliability under real conditions. In iOS development, an in-app purchase flow that works in the Xcode Simulator says nothing about how it behaves in App Store sandbox with network latency and Ask to Buy approvals. In an exam, a 100% score on an untimed quiz tells you nothing about whether you can do 49/50 in 45 minutes with no second guesses. Build for the hardest realistic case from the start.
- Skipping the first-principles documentation. Every system has a canonical specification. App Review Guidelines for iOS, the official EU regulations for tax deductibility, the CITB question bank for CSCS, the OMIE market rules for Spanish electricity. Reading them takes a few hours but saves weeks of wrong-direction work. Secondary sources (blogs, tutorials, this article included) are useful as orientation but never authoritative.
- Ignoring the rate limit. Every external system has rate limits — explicit (APNs silent push throttling, RevenueCat API quotas, exam retake fees) or implicit (App Review patience, customer attention spans, your own working memory). Plan around them. A workflow that requires more rate-limited operations than the system allows will fail in production, not on day one but during the first stress event.
- Underweighting localisation and regional variation. What is true for Germany is not always true for Italy. What is true for English-speaking users is not always true for Japanese ones. What is true for the UK CSCS test is not always true for the Irish equivalent. Always check the local rule before applying a general one.
- Treating the documentation as static. Apple updates App Review Guidelines. The Bundeslaender change Schonzeiten. OMIE adjusts market clearing algorithms. Set up a periodic review (quarterly is enough for most things) and re-read the canonical sources. Workflows that worked perfectly a year ago can be silently broken today.
None of these are dramatic. The dramatic mistakes (catastrophic bugs, audit findings, exam failures) are the visible tip of a longer-running iceberg of small misses. Catching the small misses is what separates routine outcomes from problematic ones.
Key takeaways
- p8 key — Server auth. ES256 JWT signed.
- Token registration — Per device. Refresh on app launch.
- Standard payload — Visible push. + custom data.
- Silent push — Background wake. remote-notification entitlement.
The pattern that runs through every section above: start with the constraint, not the wishlist. In an exam, the constraint is the question bank and the pass mark. In an electricity market, it is the auction clearing rule. In a tax workflow, it is the receipt-retention requirement. In a code architecture, it is the platform's design decision (StoreKit's transaction lifecycle, App Review's guideline, APNs's authentication model). Get the constraint right and the rest follows.
The opposite failure mode — designing for an aesthetic ideal, then trying to retro-fit the constraint — is the most common cause of wasted work in every domain covered here. A beautiful paywall that hangs in sandbox is rejected at App Review. A polished freelancer expense report that lacks receipts is disallowed by the tax office. A study plan that ignores the actual question distribution leaves the candidate stuck below the pass mark.
The practical recommendation: read the official rules of whatever system you are operating in, extract the binding constraints, and treat them as inputs to the design — not afterthoughts. Every section of this article is the application of that principle to a specific domain.
FAQ
Should I use p8 or p12 for new projects?
Always p8. They never expire (p12 must be renewed yearly), are scoped to your team rather than a specific app, and integrate cleanly with modern JWT signing. The legacy p12 path is only worth maintaining for existing infrastructure.
Can I send pushes without a server?
Not for production. APNs requires authenticated HTTPS requests. You can hack together test pushes from your dev machine with curl, but production pushes need a server.
How often can I send silent pushes?
Apple throttles to roughly 2-3 per hour per device for typical apps. Aggressive silent push usage hits stricter limits. Don't use silent pushes for real-time data; use them for cache invalidation.
Do I need different APNs setup for sandbox vs production?
Yes. The APNs endpoint differs: api.sandbox.push.apple.com for TestFlight/development, api.push.apple.com for App Store builds. The p8 key works for both - only the endpoint changes.
Further reading and references
The references below cover the official sources for the rules cited in this article. Where applicable, they include the canonical documentation, regulatory text, or vendor-provided guides. For each one, prefer the official source over secondary commentary — secondary sources go stale fast and frequently misquote the binding rule.
- Official documentation of the system in question (linked from each app or service's own help centre).
- Apple Developer Documentation for any iOS/macOS reference — the WWDC session videos and the corresponding Human Interface Guidelines pages are the authoritative source.
- For EU regulatory questions (taxation, data protection, energy market structure), consult the relevant national authority — most publish their guidance in English.
- For Spain and Italy energy market data, OMIE and GME both publish full historical price series in CSV format from their public websites — no API key required.
- For UK CSCS prep, the CITB publishes the official question bank book each year — buy a current copy if you want the authoritative source.
If you find a contradiction between this article and an official source, the official source wins. Article rules of thumb are summaries — they have edge cases, exceptions, and regional variations that the source documents specify exactly.
iOS push notification setup
End-to-end APNs setup: server-side p8 signing, device token sync, payload routing, deep-link handling.
Book a discovery call