Mobile Push Notification Expert
Expert in implementing push notifications across iOS and Android with FCM, APNs, rich content, and deep linking.
Activation Triggers
Activate on: "push notifications", "FCM setup", "APNs configuration", "notification channels", "deep link notification", "rich notification", "notification permissions", "silent push", "notification grouping"
NOT for: In-app messaging → react-native-architect | Email notifications → devops-automator | SMS → api-architect
Quick Start
- Configure platform credentials — APNs key (iOS) and FCM server key (Android)
- Install notification library —
@react-native-firebase/messaging or expo-notifications
- Request permissions — iOS requires explicit permission; Android 13+ requires POST_NOTIFICATIONS
- Register device token — send token to backend on registration and refresh
- Handle notification tap — deep link to the relevant screen based on notification data
Core Capabilities
| Domain |
Technologies |
| Services |
Firebase Cloud Messaging (FCM v1 API), APNs, Amazon SNS |
| Libraries |
@react-native-firebase/messaging, expo-notifications, Notifee |
| Rich Content |
Images, action buttons, custom sounds, notification extensions |
| Channels |
Android notification channels, iOS categories, grouping |
| Backend |
FCM v1 HTTP API, APNs HTTP/2, OneSignal, Knock |
Architecture Patterns
Notification Handling Flow
Backend sends push
│
├─ App in FOREGROUND:
│ ├─ onMessage handler fires
│ ├─ Show in-app toast/banner (NOT system notification)
│ └─ Update badge count
│
├─ App in BACKGROUND:
│ ├─ System shows notification
│ ├─ onNotificationOpenedApp fires on tap
│ └─ Navigate to deep link target
│
└─ App KILLED:
├─ System shows notification
├─ getInitialNotification on cold start
└─ Navigate after app initialization
FCM v1 API Payload Structure
// Server-side: send notification via FCM v1 HTTP API
const message = {
token: deviceToken,
notification: {
title: 'New Order #1234',
body: 'Your order has been confirmed',
image: 'https://cdn.example.com/order-confirmed.png',
},
data: {
type: 'order_update',
orderId: '1234',
deepLink: 'myapp://orders/1234',
},
android: {
priority: 'high',
notification: {
channelId: 'orders',
clickAction: 'OPEN_ORDER',
color: '#4A90D9',
},
},
apns: {
payload: {
aps: {
sound: 'order_confirmed.wav',
badge: 1,
'mutable-content': 1, // Enable Notification Service Extension
'thread-id': 'orders', // Group notifications
},
},
},
};
Android Notification Channels
import notifee, { AndroidImportance } from '@notifee/react-native';
// Create channels on app start (Android 8+)
async function createNotificationChannels() {
await notifee.createChannelGroup({ id: 'general', name: 'General' });
await notifee.createChannel({
id: 'orders',
name: 'Order Updates',
groupId: 'general',
importance: AndroidImportance.HIGH,
sound: 'order_notification',
vibration: true,
lights: true,
lightColor: '#4A90D9',
});
await notifee.createChannel({
id: 'messages',
name: 'Messages',
groupId: 'general',
importance: AndroidImportance.HIGH,
sound: 'message_notification',
});
await notifee.createChannel({
id: 'promotions',
name: 'Promotions',
groupId: 'general',
importance: AndroidImportance.LOW, // Users can customize
});
}
Anti-Patterns
- Sending notifications without permission — Android 13+ requires runtime permission (
POST_NOTIFICATIONS). Request it at a contextually appropriate moment, not on first launch.
- Data-only payloads for visible notifications — data-only messages on iOS require background modes and do not show alerts. Use the
notification field for visible content.
- Single notification channel — all notifications at the same priority. Create separate channels (orders, messages, promotions) so users can customize per category.
- Not handling token refresh — device tokens change on app reinstall, OS update, or token rotation. Listen for
onTokenRefresh and update the backend.
- Ignoring notification grouping — 10 individual notifications from the same app annoy users. Group by thread/topic on both iOS (
thread-id) and Android (group).
Quality Checklist
[ ] APNs key and FCM credentials configured
[ ] Permission requested at contextual moment (not first launch)
[ ] Device token registered and refresh handled
[ ] Foreground, background, and killed states all handled
[ ] Deep link navigation from notification tap
[ ] Android notification channels created per category
[ ] Rich notifications with images and action buttons
[ ] Notification grouping by topic/thread
[ ] Silent push for background data refresh
[ ] Badge count management (increment/clear)
[ ] Notification analytics tracked (delivered, opened, dismissed)
[ ] Token cleanup for uninstalled apps (periodic prune)
1---2name: mobile-push-notification-expert3description: Mobile push notification expert for FCM, APNs, deep linking, rich notifications, and notification channels. Activate on: push notifications, FCM setup, APNs configuration, notification channels, deep link from notification, rich notification, notification permissions, silent push. NOT for: in-app messaging (use react-native-architect), email notifications (use devops-automator), SMS (use api-architect).4license: Apache-2.05---67# Mobile Push Notification Expert89Expert in implementing push notifications across iOS and Android with FCM, APNs, rich content, and deep linking.1011## Activation Triggers1213**Activate on:** "push notifications", "FCM setup", "APNs configuration", "notification channels", "deep link notification", "rich notification", "notification permissions", "silent push", "notification grouping"1415**NOT for:** In-app messaging → `react-native-architect` | Email notifications → `devops-automator` | SMS → `api-architect`1617## Quick Start18191. **Configure platform credentials** — APNs key (iOS) and FCM server key (Android)202. **Install notification library** — `@react-native-firebase/messaging` or `expo-notifications`213. **Request permissions** — iOS requires explicit permission; Android 13+ requires POST_NOTIFICATIONS224. **Register device token** — send token to backend on registration and refresh235. **Handle notification tap** — deep link to the relevant screen based on notification data2425## Core Capabilities2627| Domain | Technologies |28|--------|-------------|29| **Services** | Firebase Cloud Messaging (FCM v1 API), APNs, Amazon SNS |30| **Libraries** | @react-native-firebase/messaging, expo-notifications, Notifee |31| **Rich Content** | Images, action buttons, custom sounds, notification extensions |32| **Channels** | Android notification channels, iOS categories, grouping |33| **Backend** | FCM v1 HTTP API, APNs HTTP/2, OneSignal, Knock |3435## Architecture Patterns3637### Notification Handling Flow3839```40Backend sends push41 │42 ├─ App in FOREGROUND:43 │ ├─ onMessage handler fires44 │ ├─ Show in-app toast/banner (NOT system notification)45 │ └─ Update badge count46 │47 ├─ App in BACKGROUND:48 │ ├─ System shows notification49 │ ├─ onNotificationOpenedApp fires on tap50 │ └─ Navigate to deep link target51 │52 └─ App KILLED:53 ├─ System shows notification54 ├─ getInitialNotification on cold start55 └─ Navigate after app initialization56```5758### FCM v1 API Payload Structure5960```typescript61// Server-side: send notification via FCM v1 HTTP API62const message = {63 token: deviceToken,64 notification: {65 title: 'New Order #1234',66 body: 'Your order has been confirmed',67 image: 'https://cdn.example.com/order-confirmed.png',68 },69 data: {70 type: 'order_update',71 orderId: '1234',72 deepLink: 'myapp://orders/1234',73 },74 android: {75 priority: 'high',76 notification: {77 channelId: 'orders',78 clickAction: 'OPEN_ORDER',79 color: '#4A90D9',80 },81 },82 apns: {83 payload: {84 aps: {85 sound: 'order_confirmed.wav',86 badge: 1,87 'mutable-content': 1, // Enable Notification Service Extension88 'thread-id': 'orders', // Group notifications89 },90 },91 },92};93```9495### Android Notification Channels9697```typescript98import notifee, { AndroidImportance } from '@notifee/react-native';99100// Create channels on app start (Android 8+)101async function createNotificationChannels() {102 await notifee.createChannelGroup({ id: 'general', name: 'General' });103104 await notifee.createChannel({105 id: 'orders',106 name: 'Order Updates',107 groupId: 'general',108 importance: AndroidImportance.HIGH,109 sound: 'order_notification',110 vibration: true,111 lights: true,112 lightColor: '#4A90D9',113 });114115 await notifee.createChannel({116 id: 'messages',117 name: 'Messages',118 groupId: 'general',119 importance: AndroidImportance.HIGH,120 sound: 'message_notification',121 });122123 await notifee.createChannel({124 id: 'promotions',125 name: 'Promotions',126 groupId: 'general',127 importance: AndroidImportance.LOW, // Users can customize128 });129}130```131132## Anti-Patterns1331341. **Sending notifications without permission** — Android 13+ requires runtime permission (`POST_NOTIFICATIONS`). Request it at a contextually appropriate moment, not on first launch.1352. **Data-only payloads for visible notifications** — data-only messages on iOS require background modes and do not show alerts. Use the `notification` field for visible content.1363. **Single notification channel** — all notifications at the same priority. Create separate channels (orders, messages, promotions) so users can customize per category.1374. **Not handling token refresh** — device tokens change on app reinstall, OS update, or token rotation. Listen for `onTokenRefresh` and update the backend.1385. **Ignoring notification grouping** — 10 individual notifications from the same app annoy users. Group by thread/topic on both iOS (`thread-id`) and Android (`group`).139140## Quality Checklist141142```143[ ] APNs key and FCM credentials configured144[ ] Permission requested at contextual moment (not first launch)145[ ] Device token registered and refresh handled146[ ] Foreground, background, and killed states all handled147[ ] Deep link navigation from notification tap148[ ] Android notification channels created per category149[ ] Rich notifications with images and action buttons150[ ] Notification grouping by topic/thread151[ ] Silent push for background data refresh152[ ] Badge count management (increment/clear)153[ ] Notification analytics tracked (delivered, opened, dismissed)154[ ] Token cleanup for uninstalled apps (periodic prune)155```