Push Notifications for Mobile Applications: APNs, FCM, Segmentation, Rich Push
A notification that arrives at wrong time, to wrong segment, or with non-working deep link — worse than no notification. User either disables them immediately or deletes the application. By various sources, rate of refusal to allow push permissions on iOS reaches 40% in first week after install — and reason is almost always irrelevance, not the mechanism itself.
How Infrastructure Works: APNs and FCM
Apple Push Notification service (APNs) — the only delivery channel on iOS. Everything else — OneSignal, Braze, Airship — wrappers over it. APNs accepts request via HTTP/2, authentication via JWT token (p8 key) or certificate. JWT is preferred: one key for all apps in account, doesn't expire annually like certificate.
Critical moment: APNs distinguishes apns-push-type — alert, background, voip, complication, fileprovider, mdm. Wrong type on iOS 13+ means background notification won't wake app. Seen projects where content-available: 1 was sent without apns-push-type: background — app didn't receive silent push on some devices, team spent a month looking for "app bug."
Firebase Cloud Messaging (FCM) on Android works via Google Play Services. For devices without GMS (Huawei, part of Chinese market), need Huawei Push Kit or direct WebSocket — separate task. FCM supports data messages (processed in onMessageReceived) and notification messages (system displays automatically if app in background). Mix them carefully: if notification block has click_action but deep link isn't registered in app, tap notification just opens main screen without navigation.
Segmentation and Targeting
Sending to everyone means quickly exhausting user loyalty. Normal segmentation is built on several levels.
Topics (FCM topics / APNs push-to-topic via OneSignal) — for broad categories: "new sales," "order status updates." User subscribes to topic via FirebaseMessaging.getInstance().subscribeToTopic("orders"). Simple, but no flexible filtering.
Segments by attributes — via OneSignal, Braze, or custom backend. Store in user profile: language, device type, last activity, LTV segment. Notification goes only to those with last_active < 7_days and plan = premium. OneSignal lets you build such filters in interface without code.
Personalized — to specific device_token. Here it's important to store tokens correctly: token updates on app reinstall, restore from backup to new phone, settings reset. On iOS use UNUserNotificationCenter + didRegisterForRemoteNotificationsWithDeviceToken, save to backend on each launch, not just first. Otherwise in 3 months 30% of tokens in database are stale.
Rich Push: images, buttons, progress bars
Standard notification with title and text gets clicked significantly less than rich push with image and action buttons. But implementing rich push is separate work on each platform.
iOS rich content requires UNNotificationServiceExtension (to modify payload, e.g., decrypt or load media) and UNNotificationContentExtension (custom UI). Extension runs in separate process with limited time and memory. If extension crashes or exceeds timeout, system shows original payload without media. Typical mistake — trying to load image via HTTP (not HTTPS): ATS blocks request, extension silently completes, user sees notification without picture.
Android with API 26+ notifications are tied to NotificationChannel. If channel created with IMPORTANCE_LOW, sound and vibration unavailable even if in payload — user's decision, changeable only via system app settings. Different notification types (transactional, marketing) should be in different channels so user can disable marketing without losing order notifications.
BigPictureStyle, MessagingStyle, InboxStyle — templates for extended notifications. MessagingStyle with Person and avatars — best choice for chats, system correctly groups and displays history.
Delivery and Conversion Analytics
Sending notification is half the work. Important to know: was it delivered, opened, did it lead to target action.
FCM gives MessageId on send, but doesn't guarantee delivery callback — by design. For tracking opens, need custom logic: on notification tap in onMessageReceived or via getInitialNotification() / onNotificationOpenedApp (OneSignal SDK), send event to analytics with notification_id.
OneSignal provides built-in delivery and CTR analytics. For more detailed analysis — integrate with Amplitude or Mixpanel via webhook on open event.
Implementation Process
Start with current implementation audit: how tokens are stored, is token update handling there, what notification types needed. If project from scratch — design architecture considering platforms and volume.
Typical stack: FCM + APNs at transport level, OneSignal or Firebase Notifications Composer for segmentation, custom backend for personalized event notifications. For large apps with >1M users, OneSignal has pricing limits — then Braze or own implementation on AWS SNS.
Timeline depends on complexity: basic FCM+APNs integration with transactional notifications — 1–2 weeks. Full system with segmentation, rich push, analytics and A/B testing content — 4–8 weeks.







