Skip to main content
Technology & EngineeringNotification Services170 lines

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.

Quick Summary26 lines
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 lines
Paste into your CLAUDE.md or agent config

Firebase 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 sendEach with 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

Get CLI access →

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.

Notification Services175L

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.

Notification Services211L

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.

Notification Services307L

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.

Notification Services209L

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.

Notification Services155L

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.

Notification Services159L