Push Notifications in iOS: The Full Guide
Everything you need to implement iOS push notifications in 2026 — APNs, permissions, rich media, silent pushes, and common mistakes to avoid.

iOS push notifications are one of the highest-ROI features you can add to a mobile app — and one of the most frequently misimplemented. Done right, they bring users back and drive real retention. Done wrong, they train users to tap “Don’t Allow.” This guide covers the full lifecycle: how APNs works, requesting permission the smart way, payload types, rich notifications, silent pushes, and the mistakes we see most often on production apps.
How iOS push notifications actually work
Apple Push Notification service (APNs) is the gateway between your server and every iOS device. The flow:
- Your app registers with APNs and receives a unique device token.
- Your app sends that token to your backend.
- When you want to notify the user, your server sends a JSON payload to APNs using HTTP/2 and a signed JWT or certificate.
- APNs delivers the notification to the device — even if the app is in the background or closed.
APNs handles delivery guarantees, certificate validation, and battery-efficient wakeups. Your job is to implement the handshake correctly and craft payloads that respect the user.
Permission: the moment that determines everything
iOS push notifications require explicit user permission. You get one prompt, and users who deny it are effectively unreachable until they go to Settings and change their mind manually — which most won’t.
When to ask
The worst time to ask is at first launch. The user hasn’t experienced any value yet and has no reason to trust you. A much better pattern:
- Show your own soft permission screen first. Explain concretely what kinds of notifications they’ll get (“We’ll notify you when your order ships” is more compelling than “Enable notifications”).
- Only call
UNUserNotificationCenter.requestAuthorizationafter the user taps a positive action on your screen. - If they decline your soft screen, respect it. Don’t spam the OS prompt.
UNUserNotificationCenter.current().requestAuthorization(
options: [.alert, .badge, .sound]
) { granted, error in
guard granted else { return }
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
Tip: Check
UNUserNotificationCenter.current().notificationSettingsbefore prompting. IfauthorizationStatusis.denied, skip the OS prompt and show a deep-link to Settings instead — showing the OS dialog when already denied does nothing.
Payload anatomy
APNs accepts a JSON payload up to 4 KB. The aps dictionary is reserved by Apple; everything outside it is custom data for your app.
{
"aps": {
"alert": {
"title": "Your order has shipped",
"subtitle": "Estimated arrival: tomorrow",
"body": "Tap to track your package in real time."
},
"badge": 1,
"sound": "default",
"thread-id": "orders",
"category": "ORDER_UPDATE"
},
"order_id": "abc-123"
}
Key fields to know:
| Field | Purpose |
|---|---|
alert | The visible notification content |
badge | Number displayed on the app icon |
sound | "default" or a custom .caf/.aiff file bundled with the app |
thread-id | Groups related notifications in Notification Center |
category | Links to UNNotificationCategory for action buttons |
content-available: 1 | Triggers a silent push (no UI, wakes the app) |
mutable-content: 1 | Triggers a Notification Service Extension before display |
interruption-level | passive, active, time-sensitive, critical |
Rich notifications
Since iOS 15, Apple has pushed developers toward richer, more contextual notifications. Two mechanisms matter most:
Notification Service Extension
Add "mutable-content": 1 to your payload, and iOS will launch your UNNotificationServiceExtension before displaying anything. Use it to:
- Download and attach an image, GIF, or video to the notification.
- Decrypt end-to-end encrypted content.
- Localize strings server-side without bloating the app bundle.
The extension has roughly 30 seconds of wall-clock time. If it times out, iOS displays the original payload unchanged.
Notification Content Extension
Lets you build a fully custom SwiftUI or UIKit view that appears when the user long-presses or force-touches a notification. Useful for music player controls, quick replies, or order status cards — interactions that would otherwise require launching the full app.
Silent push notifications
Set "content-available": 1 with no alert key and iOS silently wakes your app in the background for ~30 seconds of processing. Use cases include pre-fetching data, syncing a local cache, and background Core Data updates. Silent pushes are rate-limited by iOS and are never guaranteed to fire immediately — don’t use them for anything time-critical. They also require the Background Modes → Remote Notifications capability in Xcode.
Interruption levels and Focus modes
interruption-level tells iOS how urgently a notification should break through Focus modes. In 2026, getting this right matters — iOS is aggressive about silencing apps that misuse time-sensitive.
- Passive — no sound, shown in Notification Center only.
- Active (default) — sound and banner.
- Time-sensitive — breaks through Focus modes; requires an entitlement and App Store Review justification.
- Critical — bypasses Do Not Disturb and the ringer switch; Apple approval required; medical/safety apps only.
Match the level to real urgency. Promotional content flagged as time-sensitive is a fast path to users revoking permission.
Common implementation mistakes
We’ve audited enough third-party codebases to see the same errors repeatedly:
- Calling
registerForRemoteNotificationsbefore permission is granted. Only call it afterrequestAuthorizationconfirmsgranted == true. - Not refreshing the device token. Tokens can change after restore, OS upgrade, or reinstall. Always sync the token returned in
application(_:didRegisterForRemoteNotificationsWithDeviceToken:)to your backend on every launch. - Storing tokens as strings with byte-conversion bugs. Extract bytes correctly; don’t rely on
.descriptiononData. - Using the wrong APNs environment. Development builds use the sandbox endpoint; production builds use the production endpoint. The wrong pairing causes silent failures.
- Ignoring
UNUserNotificationCenterDelegate. WithoutuserNotificationCenter(_:willPresent:withCompletionHandler:), notifications won’t show while your app is in the foreground. - No analytics on delivery and open rates. Without measuring opt-out rate, you’re flying blind.
Testing push notifications in development
- Xcode 14+ lets you drag a
.apnsJSON file onto the simulator — no real device or server needed. - Terminal:
xcrun simctl push <device_id> <bundle_id> payload.apns - For real devices, use a push testing tool with your APNs
.p8key.
Always test on a real device before release; simulator behavior and true APNs delivery differ, especially for background modes.
Push notification strategy: what actually drives retention
The technical implementation is the easy part. The hard part is deciding when to send, what to say, and how often. A few principles we apply across our shipped apps:
- Relevance beats frequency. One highly relevant notification per week beats five generic ones per day. High-volume irrelevant pushes are the fastest way to lose notification permission.
- Personalize at the payload level. Use your custom payload keys to tailor the notification body per user segment — not just a generic blast.
- Measure opt-out rate. If users are disabling notifications inside your app settings (or uninstalling), your notification strategy is the first place to look.
- Use notification grouping. Set
thread-idso multiple notifications from the same context collapse into a single thread in Notification Center rather than flooding the lock screen.
How push notifications fit into app cost and timeline
Push notifications are a mid-complexity feature when budgeting an iOS project. A basic APNs integration adds roughly 1–2 weeks; rich notifications with a custom content extension, analytics, and segmentation are closer to 3–4 weeks. A standard iOS app with auth, payments, and an API backend runs $15–45k over 4–7 months — see the full cost breakdown for context. Notifications are almost always included in that scope.
iOS push notifications are deceptively deep. The basics take an afternoon; getting permissions, payload design, background handling, and user experience right takes deliberate engineering and ongoing measurement.
If you’re building an iOS app and want this done correctly from day one — or you’re inheriting a codebase with a broken notification setup — talk to us. We’ll scope it clearly and build it to stay.
Building something like this?
Fera Tech ships iOS & full-stack apps end-to-end. Tell us about your project.
Start a project