Firebase Cloud Messaging logo

firebase cloud messaging

Cross platform push notifications and messaging

$ npx docs2skills add firebase-cloud-messaging
SKILL.md
scaling-optimization.md
message-customization.md
targeting-user-groups.md
server-sending-messages.md
client-setup-integration.md

Firebase Cloud Messaging

Cross-platform push notifications and real-time messaging service that delivers messages reliably to iOS, Android, and web clients with advanced targeting and 4KB payload support.

What this skill does

Firebase Cloud Messaging (FCM) is Google's cross-platform messaging solution that enables you to send push notifications and data messages to client applications. FCM handles the complexity of message delivery across different platforms, automatically routing messages through Apple Push Notification service (APNs) for iOS, Google's transport layer for Android, and web push protocol for browsers.

Unlike basic push notification services, FCM provides sophisticated message targeting (single devices, device groups, topic subscriptions), message customization per platform, delivery analytics, and guaranteed message delivery with automatic retries. It supports both notification messages (handled by the system) and data messages (processed by your app logic), making it suitable for everything from marketing notifications to real-time chat applications.

FCM solves the critical challenges of mobile engagement: reaching users across platforms reliably, handling device token management automatically, providing delivery insights, and scaling to millions of devices without managing infrastructure.

Prerequisites

  • Firebase project with FCM enabled
  • Platform-specific setup:
    • iOS: Apple Developer account, APNs certificate/key, Xcode project
    • Android: Google Play services, compileSdkVersion 21+
    • Web: HTTPS domain, service worker support
  • Server environment for sending messages (Node.js, Python, Java, etc.)
  • Firebase Admin SDK or FCM v1 API credentials

Quick start

Install the SDK for your platform:

# iOS (CocoaPods)
pod 'Firebase/Messaging'

# Android (Gradle)
implementation 'com.google.firebase:firebase-messaging:23.4.0'

# Web
npm install firebase

# Server (Node.js)
npm install firebase-admin

Basic client setup to receive messages:

// Web
import { initializeApp } from 'firebase/app';
import { getMessaging, getToken, onMessage } from 'firebase/messaging';

const app = initializeApp(firebaseConfig);
const messaging = getMessaging(app);

// Get registration token
getToken(messaging, { vapidKey: 'YOUR_VAPID_KEY' }).then((token) => {
  console.log('Registration token:', token);
});

// Handle foreground messages
onMessage(messaging, (payload) => {
  console.log('Message received:', payload);
});

Send a message from server:

// Node.js Admin SDK
const admin = require('firebase-admin');
admin.initializeApp();

const message = {
  notification: {
    title: 'Hello World',
    body: 'This is a test notification'
  },
  token: 'USER_DEVICE_TOKEN'
};

admin.messaging().send(message)
  .then(response => console.log('Successfully sent:', response));

For complete client setup across all platforms, read the client-setup-integration.md file in this skill directory.

Core concepts

Registration Tokens: Unique identifiers for app installations. Automatically generated and must be sent to your server for targeting specific devices.

Message Types:

  • Notification messages: Displayed by the system, handled automatically
  • Data messages: Custom key-value pairs processed by your app

Message Targeting:

  • Single device: Send to specific registration token
  • Device groups: Send to multiple devices owned by single user
  • Topics: Send to devices subscribed to named topics (e.g., "news", "sports")

Transport Layers: FCM routes messages through platform-specific services (APNs for iOS, FCM connection server for Android, web push for browsers).

Message Priority: Controls delivery timing and device wake behavior. High priority wakes sleeping devices, normal priority respects device power management.

Message Lifecycle: Messages have TTL (time-to-live), can be collapsible (replaced by newer messages), and support delivery receipts.

For server-side implementation details, read the server-sending-messages.md file in this skill directory.

Key API surface

Client APIs (receiving messages):

// Get registration token
getToken(messaging, { vapidKey }) → Promise<string>

// Handle foreground messages  
onMessage(messaging, callback) → Unsubscribe

// Subscribe to topic
import { getMessaging } from 'firebase/messaging';
// Server-side subscription required

// Handle background messages (service worker)
onBackgroundMessage(messaging, callback) → void

Admin SDK (sending messages):

// Send single message
admin.messaging().send(message) → Promise<string>

// Send to multiple devices
admin.messaging().sendMulticast(message) → Promise<BatchResponse>

// Send to topic
admin.messaging().sendToTopic(topic, message) → Promise<MessagingTopicResponse>

// Manage topic subscriptions
admin.messaging().subscribeToTopic(tokens, topic) → Promise<MessagingTopicManagementResponse>
admin.messaging().unsubscribeFromTopic(tokens, topic) → Promise<MessagingTopicManagementResponse>

FCM v1 REST API:

POST https://fcm.googleapis.com/v1/projects/PROJECT_ID/messages:send
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json

Common patterns

Basic notification with data:

const message = {
  notification: {
    title: 'Order Update',
    body: 'Your order #1234 has been shipped'
  },
  data: {
    orderId: '1234',
    status: 'shipped',
    trackingUrl: 'https://track.example.com/1234'
  },
  token: userToken
};

admin.messaging().send(message);

Topic-based messaging:

// Subscribe users to topics (server-side)
admin.messaging().subscribeToTopic([userToken1, userToken2], 'breaking-news');

// Send to topic subscribers
const topicMessage = {
  notification: {
    title: 'Breaking News',
    body: 'Important update available'
  },
  topic: 'breaking-news'
};

admin.messaging().send(topicMessage);

Conditional topic messaging:

const message = {
  notification: {
    title: 'Sports Update'
  },
  condition: "'football' in topics && ('premier-league' in topics || 'champions-league' in topics)"
};

Platform-specific customization:

const message = {
  notification: {
    title: 'New Message',
    body: 'You have a new message'
  },
  android: {
    notification: {
      icon: 'stock_ticker_update',
      color: '#f45342',
      sound: 'custom_sound'
    }
  },
  apns: {
    payload: {
      aps: {
        sound: 'custom_sound.caf',
        badge: 1
      }
    }
  },
  webpush: {
    notification: {
      icon: '/icon-192x192.png',
      actions: [
        { action: 'reply', title: 'Reply' }
      ]
    }
  },
  token: userToken
};

Batch messaging with error handling:

const tokens = ['token1', 'token2', 'token3'];
const message = {
  notification: {
    title: 'Bulk Update',
    body: 'Important announcement'
  }
};

const response = await admin.messaging().sendMulticast({
  tokens,
  ...message
});

console.log(`${response.successCount} messages sent successfully`);
response.responses.forEach((resp, idx) => {
  if (!resp.success) {
    console.log(`Failed to send to ${tokens[idx]}: ${resp.error}`);
  }
});

For advanced message customization options, read the message-customization.md file in this skill directory.

Configuration

Firebase project setup:

// firebase-config.js
export const firebaseConfig = {
  apiKey: "your-api-key",
  authDomain: "project.firebaseapp.com",
  projectId: "your-project-id",
  messagingSenderId: "123456789",
  appId: "your-app-id"
};

Service worker (web):

// firebase-messaging-sw.js
importScripts('https://www.gstatic.com/firebasejs/9.0.0/firebase-app-compat.js');
importScripts('https://www.gstatic.com/firebasejs/9.0.0/firebase-messaging-compat.js');

firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();

messaging.onBackgroundMessage((payload) => {
  const notificationOptions = {
    body: payload.notification.body,
    icon: '/firebase-logo.png'
  };

  self.registration.showNotification(payload.notification.title, notificationOptions);
});

Admin SDK initialization:

const admin = require('firebase-admin');
const serviceAccount = require('./path/to/serviceAccountKey.json');

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  projectId: 'your-project-id'
});

Environment variables:

FIREBASE_PROJECT_ID=your-project-id
GOOGLE_APPLICATION_CREDENTIALS=./serviceAccountKey.json
FCM_VAPID_KEY=your-vapid-key

For user targeting and topic management details, read the targeting-user-groups.md file in this skill directory.

Best practices

Token management: Always refresh registration tokens on app start and when onTokenRefresh fires. Store tokens server-side with user associations and remove invalid tokens from your database.

Message payload optimization: Keep notification titles under 50 characters and bodies under 120 characters for optimal display. Use data messages for large payloads and custom processing.

Topic naming: Use clear, hierarchical topic names (news.sports.football, not topic1). Limit topic subscriptions per device to avoid performance issues.

Platform-specific handling: Customize messages per platform using android, apns, and webpush objects. Different platforms have varying notification limits and behaviors.

Error handling: Always handle messaging/registration-token-not-registered errors by removing invalid tokens. Implement exponential backoff for retry logic.

Testing strategy: Use Firebase Console Notifications composer for quick testing. Create separate topics for development and production environments.

Message priority: Use high priority sparingly - only for time-sensitive messages like calls or critical alerts. Normal priority respects device battery optimization.

Data vs notification: Use notification messages for user-visible alerts, data messages for silent updates or when you need custom notification handling.

Security: Never expose server keys client-side. Use Firebase Security Rules and Admin SDK for server operations. Validate all data message payloads.

Analytics integration: Enable message delivery reports and integrate with Google Analytics for comprehensive messaging insights.

Gotchas and common mistakes

iOS simulator limitations: FCM doesn't work on iOS simulators - only physical devices support push notifications. Test on real devices only.

Web HTTPS requirement: FCM web requires HTTPS domains. localhost works for development, but production must use SSL certificates.

Service worker registration: Web background messages only work with registered service workers. Messages are lost if service worker isn't properly configured.

Android app in background: Notification messages are handled by system when app is backgrounded. Data messages can still reach your app logic.

Token invalidation: Registration tokens can become invalid when app is restored from backup, uninstalled/reinstalled, or on new device. Always handle token refresh.

Message size limits: Total message payload cannot exceed 4KB across all platforms. Large data should be sent as message identifiers with separate API calls.

APNs certificate expiration: iOS push certificates expire annually and must be renewed. Use APNs auth keys for tokens that don't expire.

Topic subscription delays: Topic subscriptions aren't instantaneous - allow 2-3 seconds before sending messages to newly subscribed topics.

Quota limits: FCM has rate limits (600,000 messages per minute for free tier). Implement proper throttling for high-volume applications.

Collapsible messages: Only the latest collapsible message with same collapse_key is delivered to offline devices. Use for updates, not individual notifications.

Cross-platform notification differences: iOS shows notifications differently than Android. Test notification appearance on all target platforms.

Web notification permissions: Users must explicitly grant notification permission. Handle permission denied gracefully and explain value proposition.

Battery optimization: Android devices may kill background apps, preventing message receipt. Guide users to whitelist your app in battery settings.

Message delivery timing: Messages aren't guaranteed to be delivered immediately. Factor in network conditions and device state in your UX design.

For scaling and optimization strategies, read the scaling-optimization.md file in this skill directory.