Skip to content
← All guides iOS

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.

Push Notifications in iOS: The Full Guide

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:

  1. Your app registers with APNs and receives a unique device token.
  2. Your app sends that token to your backend.
  3. When you want to notify the user, your server sends a JSON payload to APNs using HTTP/2 and a signed JWT or certificate.
  4. 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.requestAuthorization after 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().notificationSettings before prompting. If authorizationStatus is .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:

FieldPurpose
alertThe visible notification content
badgeNumber displayed on the app icon
sound"default" or a custom .caf/.aiff file bundled with the app
thread-idGroups related notifications in Notification Center
categoryLinks to UNNotificationCategory for action buttons
content-available: 1Triggers a silent push (no UI, wakes the app)
mutable-content: 1Triggers a Notification Service Extension before display
interruption-levelpassive, 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:

  1. Calling registerForRemoteNotifications before permission is granted. Only call it after requestAuthorization confirms granted == true.
  2. 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.
  3. Storing tokens as strings with byte-conversion bugs. Extract bytes correctly; don’t rely on .description on Data.
  4. Using the wrong APNs environment. Development builds use the sandbox endpoint; production builds use the production endpoint. The wrong pairing causes silent failures.
  5. Ignoring UNUserNotificationCenterDelegate. Without userNotificationCenter(_:willPresent:withCompletionHandler:), notifications won’t show while your app is in the foreground.
  6. 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 .apns JSON 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 .p8 key.

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-id so 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
Call us Open business Telegram