Push Notifications in 2026: Why You Should Stop Managing Your Own Infrastructure

Editorial team
Dot
October 5, 2026
Push notifications in 2026 – why stop managing your own infrastructure and centralize cross-platform targeting, multilingual messaging and delivery tracking

The ops burden of self-managed push has compounded quietly for years. Here's the honest accounting, and what a unified platform actually looks like

‍

The Real Cost of Self-Managed Push

Push notifications look simple on paper: call an API, a message appears on a device. In production, teams running push at scale are quietly maintaining a second infrastructure layer with its own failure modes, credential lifecycle, and incident surface.

The operational costs that accumulate over time:


Credential management:
Push credentials are long-lived secrets that live in secrets managers, CI pipelines, and occasionally in repositories where they should not be. Every new team member needs access. Every credential rotation requires updates across every service that sends notifications. When a credential expires or is revoked, every send silently fails.

‍

Per-platform implementation:  iOS and Android have different push APIs, different authentication mechanisms, different payload structures, different error codes, and different retry semantics. Every React Native, Flutter, or native version bump is a potential regression on either or both platforms. A team shipping to both platforms is maintaining two distinct push implementations.

Delivery analytics are DIY:  Platform push APIs return delivery receipts only at the send layer - whether the message reached the provider's server, not whether it reached the device or was opened. Open rates, conversion tracking, and segment-level analytics require a separate pipeline that someone must build and maintain.

Retry and token hygiene:  Push APIs return error codes requiring conditional retry logic - rate limits, invalid tokens, temporary unavailability. Tokens for uninstalled apps accumulate in databases and inflate send counts. Cleaning stale tokens is an ongoing maintenance task, not a one-time setup.


Incident response:
 When a push provider changes an API, deprecates a credential format, or experiences an outage, the on-call engineer is responsible for the response. The knowledge of how the system works concentrates on whoever set it up.

‍

‍

What Changed in 2024–2026

FCM Legacy API Shutdown - June 20, 2024

‍

Google shut down the FCM Legacy HTTP API and FCM XMPP API on June 20, 2024. Teams that had not migrated to the FCM HTTP v1 API  (OAuth 2.0) had push outages. The migration required:

- Replacing simple API keys with OAuth 2.0 service account credentials (a JSON key file)

- Updating server-side send code to the v1 payload format

- Handling OAuth token refresh (tokens expire every 60 minutes)

- Updating third-party push libraries that abstracted the legacy API

The v1 API uses per-request OAuth 2.0 tokens generated from the service account:

http
POST https://fcm.googleapis.com/v1/projects/PROJECT_ID/messages:send
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json
{
  "message": {
    "token": "DEVICE_FCM_TOKEN",
    "notification": {
      "title": "New build ready",
      "body": "v2.4.1 is available for testing"
    },
    "android": {
      "priority": "high"
    },
    "apns": {
      "headers": {
        "apns-priority": "10"
      }
    }
  }
}

‍

APNs: Token-Based Authentication Is the Standard

Apple deprecated certificate-based APNs authentication (`.p12` files) years ago. Token-based authentication using `.p8` keys is the current standard and the only path forward.

‍

How it works:

1. You generate a `.p8` private key in Apple Developer portal (one key can be used for all your apps)

2. Your server uses the `.p8` key to sign a JWT (JSON Web Token)

3. The JWT is sent with every APNs request in the `Authorization` header

4. JWTs expire after 60 minutes - your server must refresh them

The `.p8` key itself does not expire, but if it is ever compromised, you revoke it in the Apple Developer portal and all services using it immediately stop working until updated.

# APNs request structure
POST /3/device/DEVICE_TOKEN HTTP/2
Host: api.push.apple.com
Authorization: Bearer SIGNED_JWT
apns-topic: com.yourcompany.yourapp
apns-push-type: alert
apns-priority: 10
Content-Type: application/json
{
  "aps": {
    "alert": {
      "title": "New build ready",
      "body": "v2.4.1 is available for testing"
    },
    "sound": "default"
  }
}

Official source:  Sending notification requests to APNs - Apple Developer Documentation

‍

iOS 27: Live Activities Use Separate Push Tokens

iOS 27 Live Activities (Dynamic Island and Lock Screen real-time updates) use a distinct push token from the standard device push token. You cannot send a Live Activity update to a standard APNs device token. If your app plans to use Live Activities:

- Your app must request a Live Activity push token separately via ActivityKit

- Your server must store, refresh, and route two token types per device

- The Live Activity push endpoint uses `apns-push-type: liveactivity`

- Live Activity tokens expire when the activity ends - your server must handle this lifecycle

‍

Official source: Starting and updating Live Activities with ActivityKit push notifications

‍

Android 13+: POST_NOTIFICATIONS Runtime Permission

Android 13 (API 33) introduced `POST_NOTIFICATIONS` as a runtime permission. This changed push notification delivery fundamentally:

  • Apps must request the permission at runtime - they cannot send notifications without it
  • Users who deny twice  cannot be re-prompted; the system suppresses all future permission dialogs from your app
  • Users who deny can only re-enable from system Settings → App → Notifications
  • targetSdkVersion 33+ makes the permission mandatory; apps targeting lower SDKs get a grace period on upgrade

The consequence: your onboarding flow must surface the value of notifications before the first prompt. A cold-open permission dialog with no context gets denied, permanently.

dart
// Flutter: request permission with permission_handler
import 'package:permission_handler/permission_handler.dart';
final status = await Permission.notification.request();
if (status.isPermanentlyDenied) {
  // Direct user to app settings -- cannot re-prompt
  openAppSettings();
}

Official source: Notification runtime permission - Android Developers

‍

‍

Rich Notifications and Background Delivery

‍

Rich Notifications (iOS)

Rich notifications - notifications that display an image, GIF, video, or a fully custom UI - are implemented via a Notification Service Extension: a separate iOS app extension that the system invokes to intercept and mutate a notification payload before it is displayed to the user.

‍

Key facts teams often miss:

The extension is a separate binary compiled into your app bundle. It has its own entitlements, its own `Info.plist`, and - since iOS 27 - its own `PrivacyInfo.xcprivacy` if it accesses any required-reason APIs (e.g., NSUserDefaults  for badge count persistence).

  • For the extension to be invoked, the APNs payload must  include "mutable-content": 1 in the aps dictionary. A payload without this flag is delivered directly to the system notification UI - the extension is never called.

  • The extension has a limited execution window (approximately 30 seconds) to download and attach media. If the download does not complete within this window, the system delivers the notification without the attachment - falling back to the plain text title and body.

  • Notification attachments (images, GIF, video) are downloaded inside the extension using URLSession and provided to the system via `UNNotificationAttachment`. Video files must not exceed the system size limit (currently 50 MB for video, 10 MB for images, 5 MB for GIF).
// APNs payload -- mutable-content required for Notification Service Extension
{
  "aps": {
    "alert": {
      "title": "New build ready",
      "body": "v2.4.1 is available. Tap to install."
    },
    "mutable-content": 1,
    "sound": "default"
  },
  "attachment-url": "https://cdn.yourcompany.com/builds/v2.4.1-thumbnail.png"
}

Official source: UNNotificationServiceExtension - Apple Developer Documentation

‍

Background Push (iOS)

Background pushes deliver a signal to the app without displaying a visible notification. They are used for silent data sync, content prefetch, and cache invalidation.

‍

  • The APNs payload must include "content-available": 1 in the `aps` dictionary and must not include alert, sound, or badge keys - a payload with both content-available and alert is treated as a regular notification, not a background push.

  • The app must have Background Modes → Remote notifications enabled in Xcode (under Signing & Capabilities). Without this capability, background pushes wake the app but application(_:didReceiveRemoteNotification:fetchCompletionHandler:) is never called.

  • iOS throttles background push delivery based on the app's background execution budget. The OS tracks how efficiently the app uses background time - apps that consume excessive CPU or return `.noData` frequently are deprioritized for future background pushes.

  • Background pushes are not guaranteed. The OS may delay or drop them when the device is in Low Power Mode, when the device is on a cellular connection rather than Wi-Fi, or when the app has exceeded its background execution budget.

‍

Official sources: 

‍

‍

Android Notification Channels (API 26+)

Android 8.0 (API 26) introduced notification channels as a required routing layer for all notifications. Every notification must be assigned to a channel - notifications sent without a valid channel ID are silently dropped on API 26+ devices.

‍

Design implications teams often get wrong:

‍

Users can disable individual channels from Settings → Apps → [Your App] → Notifications. If your app uses a single channel for all notifications and the user disables it, all notifications stop. The app has no way to re-enable the channel - only the user can do so from Settings.

  • Design at minimum two channels: one for transactional or critical notifications (account security, order confirmations, build alerts) and one for marketing or informational content (promotions, newsletters, tips). This lets users opt out of marketing noise without losing critical alerts.

  • Channel configuration - sound, vibration pattern, importance level (`IMPORTANCE_HIGH`, `IMPORTANCE_DEFAULT`, etc.), and whether to show a badge - is set at channel creation time. Once a channel is created on a user's device, the app cannot change these values programmatically. Only the user can modify channel settings from the system UI. If you create a channel with the wrong importance level, the only fix is to create a new channel with a new ID.

‍

// Android: create notification channels at app startup
val channelTransactional = NotificationChannel(
    "transactional",
    "Account & Order Alerts",
    NotificationManager.IMPORTANCE_HIGH
).apply {
    description = "Security alerts, order confirmations, and build notifications"
    enableVibration(true)
}
val channelMarketing = NotificationChannel(
    "marketing",
    "Promotions & Tips",
    NotificationManager.IMPORTANCE_DEFAULT
).apply {
    description = "Product updates, tips, and promotional content"
}
val notificationManager = getSystemService(NotificationManager::class.java)
notificationManager.createNotificationChannels(listOf(channelTransactional, channelMarketing))

Official source:  Create and manage notification channels - Android Developers

‍

The Operational Overhead: Self-Managed vs Unified Platform

Area Self-managed Unified platform
Initial setup Days - platform credentials, server-side send logic, token storage schema, retry logic Hours - single SDK + credential setup in portal
Credential management Manual - stored in secrets manager, referenced in multiple services Managed - single credential entry per platform
Credential rotation Manual update across all services, potential for outage Managed in portal
Per-platform SDK updates Each platform independently, separate version cycles Single version
Delivery analytics Custom pipeline required for open rates, segments Built-in dashboards
Targeting and segmentation Build it yourself against your user database Segment builder included
Retry logic Custom implementation - exponential backoff, conditional retry by error code Handled at platform layer
Token hygiene Manual cleanup of uninstalled app tokens Automatic stale token removal
Live Activity token routing Custom storage and routing logic Handled by platform
Incident response Your on-call, your runbook Platform provider handles API changes
Multi-environment (staging/prod) Separate credential sets, separate send paths Environments managed in portal

‍

‍

AppsOnAir Push Notifications - Beta

AppsOnAir Push Notifications extends the OTA distribution platform with a unified push delivery layer, currently in beta.

‍

What it covers:

  • Delivery to iOS and Android from a single integration - no per-platform send logic on your server
  • Targeting segments - send to specific app versions, device groups, or custom segments you define
  • Open rate and delivery analytics out of the box - no custom pipeline required
  • Advanced notification for mobile platforms. 

‍

Setup is required:

You can configure your platform push credentials once in the AppsOnAir portal, integrate the SDK into your app, and route sends through the API or portal UI. This is not a zero-configuration service - push delivery requires your APNs and FCM credentials. The difference is that you configure them once in one place, not once per service that sends notifications.

‍

If you are already using AppsOnAir for OTA distribution, the same portal and SDK surface handles push. Same app, same team, same distribution groups - push targeting maps directly to your existing OTA segments.

‍

Get started: AppsOnAir Push Notification

‍

Migration Checklist:

For teams moving from self-managed push:

  • Setup Push notification configuration on AppsOnAir portal (onetime setup).
  • Export Notification data from existing platforms.
  • Import Exported data on AppsOnAir web portal.
  • Integrate SDK on your mobile applications. 

‍

‍

Token Management in Production:

Token hygiene is one of the most consistently underbuilt parts of push infrastructure. The issues below are well-documented in platform documentation but rarely addressed until they cause production failures.

‍

Token lifecycle facts teams often miss

iOS push token rotation:  APNs device tokens are not permanent. A token can change after an app reinstall, after an iOS major version update, or at Apple's discretion as part of its security model. Your server must handle token updates: when the app launches an application(_:didRegisterForRemoteNotificationsWithDeviceToken:) fires, compare the new token against the stored value and update your server if it has changed. If a send request to APNs returns a `BadDeviceToken` or `Unregistered` error response, remove that token from your database immediately. Continued sends to invalid tokens are tracked by APNs and can result in rate limiting of your sending endpoint.

Android FCM token refresh:  FCM device registration tokens are refreshed when the app is restored from a backup on a new device, when the app is uninstalled and reinstalled, or when the user clears app data from Settings. Implement `FirebaseMessaging.instance.onTokenRefresh` as a persistent listener in your app initialization path to capture new tokens and push them to your server. A token refresh that goes undelivered to your server means that device stops receiving notifications until the next app launch that triggers the token update.

‍

Token deduplication: Internal builds, development builds, and production builds installed on the same device under the same user account each produce a distinct push token. Without deduplication scoped by appId and bundleIdentifier (iOS) or applicationId (Android), every notification sends to all installs simultaneously. Scope token storage by the combination of userId + appId + bundleIdentifier, not by userId alone.

‍

Silent deactivation rate:

 At scale, 2–5% of a registered token base becomes invalid monthly - from device replacements, uninstalls, and iOS token rotation. Sending to stale tokens wastes push provider capacity and inflates delivery and open rate metrics (a send to an invalid token is counted as a send but never reaches a device). Stale token cleanup must run on a schedule - reactive cleanup on error response alone is not sufficient at this rate. Implement a periodic sweep that removes tokens not refreshed within a defined window (commonly 60–90 days).

‍

Official sources:

‍

‍

When Should You Use a Unified Push Platform?

‍

Multiple platforms: You maintain both APNs and FCM infrastructure.

Growing user base: Token management, retries, and delivery analytics become operational concerns.

Multiple environments: Staging, production, and multiple apps require increasingly complex credential management.

Small mobile/DevOps teams: Reducing infrastructure ownership lets the team focus on product development.

‍

‍

Conclusion

Push notifications are no longer just an API integration. As mobile platforms evolve, teams must continuously manage credentials, platform changes, token lifecycles, retries, analytics, and production incidents across iOS and Android.

For teams that want to keep full control, self-managed infrastructure can still be the right choice. But for teams looking to reduce operational overhead and move faster, a unified push platform can centralize the complexity while providing the tooling needed for reliable delivery at scale.

The goal is not simply to send a notification.  It is to build a push infrastructure that remains reliable, maintainable, and adaptable as mobile platforms change.

With AppsOnAir Push Notifications now in beta, teams can centralize push configuration, delivery, targeting, and analytics alongside their existing mobile distribution workflow.

FAQ’s

No items found.

Actionable Insights,
Straight to Your Inbox

Subscribe to our newsletter to get useful tutorials , webinars,use cases, and step-by-step guides from industry experts

Start Pushing Real-Time App Updates Today
Try AppsOnAir for Free
Stay Uptodate