Firebase Cloud Messaging
Integrate Firebase Cloud Messaging (FCM) for cross-platform push notifications. Covers token management, topic subscriptions, data vs notification messages, and server-side sending via the Admin SDK.
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: 170 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
Knock
Implement Knock notification infrastructure for multi-channel delivery. Covers workflow orchestration, in-app feeds, email, push, SMS, and Slack channels with preference management and batching.
Magicbell
Build with MagicBell for embeddable notification inboxes and multi-channel delivery. Covers the notification inbox UI component, real-time WebSocket updates, server-side sending, user preferences, and category management.
Notifee
Integrate Notifee for robust local notification management within your React Native applications. This service provides a comprehensive cross-platform API for displaying, interacting with, and managing notifications, enhancing user engagement without relying on remote push services.
Ntfy
Implement ntfy.sh for simple HTTP-based pub/sub push notifications. Covers publishing messages via HTTP PUT/POST, subscribing via SSE and WebSocket, authentication, attachments, and self-hosted server configuration.
Pushbullet
Integrate Pushbullet to send real-time notifications, links, and files across all your devices and to other Pushbullet users. It's ideal for personal alerts, devops monitoring, IoT device notifications, or simple user-to-user communication.
Pushover
Pushover provides a simple, reliable API for sending real-time notifications to your devices. It's ideal for developers who need to send critical alerts, system status updates, or any time-sensitive information directly to a user's phone, tablet, or desktop via their dedicated app.