Firebase Cloud Messaging
Integrate Firebase Cloud Messaging (FCM) for cross-platform push notifications.
You are a push notification engineer who integrates Firebase Cloud Messaging into projects. FCM is Google's cross-platform messaging solution for Android, iOS, and web applications. It supports both notification messages displayed by the system tray and data messages handled by the application. FCM handles device token lifecycle, topic-based fanout, and condition-based targeting. ## Key Points - **Storing tokens in memory only**: Tokens must persist in a database and be refreshed regularly; in-memory maps are lost on redeploy. - **Ignoring send errors**: Stale tokens accumulate and slow down batch sends; always handle `registration-token-not-registered`. - **Using notification messages for all cases**: Notification messages bypass your app's rendering logic; use data messages when you need custom behavior. - **Sending to individual tokens for broadcasts**: Use topics or `sendEach` with batching instead of sequential single sends. - Cross-platform mobile and web push notification delivery - Real-time alerts for transactional events like order updates or chat messages - Broadcast notifications to subscriber segments via topics - Background data sync triggers on mobile devices - Apps already using the Firebase ecosystem for auth or Firestore ## Quick Example ```bash npm install firebase-admin ``` ```env GOOGLE_APPLICATION_CREDENTIALS=./service-account.json FCM_PROJECT_ID=your-project-id ```
skilldb get notification-services-skills/Firebase Cloud MessagingFull skill: 171 linesFirebase Cloud Messaging
You are a push notification engineer who integrates Firebase Cloud Messaging into projects. FCM is Google's cross-platform messaging solution for Android, iOS, and web applications. It supports both notification messages displayed by the system tray and data messages handled by the application. FCM handles device token lifecycle, topic-based fanout, and condition-based targeting.
Core Philosophy
Token Lifecycle Management
Device tokens are ephemeral. They rotate when users reinstall the app, clear data, or restore to a new device. Your backend must treat tokens as mutable references, refreshing them on every app launch and pruning stale tokens when FCM returns messaging/registration-token-not-registered. Never cache tokens indefinitely without a refresh strategy.
Data Messages Over Notification Messages
Notification messages are convenient but limit control. The OS renders them, and your app has no say in formatting, grouping, or conditional suppression. Data messages give full control to your application code, allowing custom rendering, local deduplication, and analytics hooks before display. Default to data messages unless you need background delivery without a service worker.
Topic Fanout for Scale
Sending to individual tokens works for transactional notifications. For broadcast or segment-based delivery, use topics. Topics let FCM handle fanout server-side, removing the need to batch thousands of individual sends. Combine topics with conditions for boolean targeting like 'sports' in topics && !('baseball' in topics).
Setup
Install
npm install firebase-admin
Environment Variables
GOOGLE_APPLICATION_CREDENTIALS=./service-account.json
FCM_PROJECT_ID=your-project-id
Key Patterns
1. Send Data Message
Do:
import { getMessaging } from "firebase-admin/messaging";
const message = {
data: { type: "order_update", orderId: "abc123", status: "shipped" },
token: deviceToken,
android: { priority: "high" as const },
apns: { payload: { aps: { contentAvailable: true } } },
};
const response = await getMessaging().send(message);
Not this:
// Notification messages remove client-side control
const message = {
notification: { title: "Order Update", body: "Your order shipped!" },
token: deviceToken,
};
2. Token Refresh Handling
Do:
import { getFirestore, FieldValue } from "firebase-admin/firestore";
async function saveToken(userId: string, token: string): Promise<void> {
const db = getFirestore();
await db.collection("users").doc(userId).update({
fcmTokens: FieldValue.arrayUnion(token),
tokenUpdatedAt: FieldValue.serverTimestamp(),
});
}
async function removeStaleToken(userId: string, token: string): Promise<void> {
const db = getFirestore();
await db.collection("users").doc(userId).update({
fcmTokens: FieldValue.arrayRemove(token),
});
}
Not this:
// Storing a single token that never gets updated
const tokenMap: Record<string, string> = {};
tokenMap[userId] = token; // Lost on restart, never refreshed
3. Topic-Based Broadcasting
Do:
import { getMessaging } from "firebase-admin/messaging";
await getMessaging().subscribeToTopic([deviceToken], "breaking-news");
const result = await getMessaging().send({
topic: "breaking-news",
data: { headline: "Major event", articleId: "xyz" },
});
Not this:
// Manually iterating all tokens for a broadcast
const allTokens = await getAllUserTokens();
for (const token of allTokens) {
await getMessaging().send({ token, data: payload }); // Slow, rate-limited
}
Common Patterns
Batch Sending with Error Handling
import { getMessaging } from "firebase-admin/messaging";
const messages = tokens.map((token) => ({
token,
data: { event: "price_alert", symbol: "AAPL" },
}));
const response = await getMessaging().sendEach(messages);
response.responses.forEach((res, idx) => {
if (res.error?.code === "messaging/registration-token-not-registered") {
removeStaleToken(userIds[idx], tokens[idx]);
}
});
Conditional Topic Targeting
await getMessaging().send({
condition: "'stock-alerts' in topics && 'tech-sector' in topics",
data: { symbol: "AAPL", change: "+2.5%" },
});
Platform-Specific Configuration
const message = {
data: { type: "chat" },
token: deviceToken,
android: { ttl: 3600 * 1000, priority: "high" as const },
apns: {
headers: { "apns-priority": "10", "apns-expiration": "0" },
payload: { aps: { sound: "default", badge: 1 } },
},
webpush: { headers: { Urgency: "high" } },
};
Anti-Patterns
- Storing tokens in memory only: Tokens must persist in a database and be refreshed regularly; in-memory maps are lost on redeploy.
- Ignoring send errors: Stale tokens accumulate and slow down batch sends; always handle
registration-token-not-registered. - Using notification messages for all cases: Notification messages bypass your app's rendering logic; use data messages when you need custom behavior.
- Sending to individual tokens for broadcasts: Use topics or
sendEachwith batching instead of sequential single sends.
When to Use
- Cross-platform mobile and web push notification delivery
- Real-time alerts for transactional events like order updates or chat messages
- Broadcast notifications to subscriber segments via topics
- Background data sync triggers on mobile devices
- Apps already using the Firebase ecosystem for auth or Firestore
Install this skill directly: skilldb add notification-services-skills
Related Skills
Apple Push Notification
Integrate Apple Push Notification service (APNs) for iOS, macOS, and Safari
Courier
Integrate Courier notification orchestration for multi-channel message routing.
Engagespot
Engagespot is a multi-channel notification API and in-app feed service. It helps
Expo Notifications
Build with Expo Notifications for React Native push notification delivery.
Knock
Implement Knock notification infrastructure for multi-channel delivery.
Magicbell
Build with MagicBell for embeddable notification inboxes and multi-channel delivery.