Firebase Topic Messaging

Topic messaging lets you send one notification to many users simultaneously without knowing each user's individual FCM token. Users subscribe to named topics — like "sports-news" or "order-updates" — and you send messages to the topic. Every subscriber receives the notification.

Topics vs Tokens

Sending to individual tokens:
- Send to User A's token
- Send to User B's token
- Send to User C's token
= 3 separate API calls, 3 tokens to manage

Sending to a topic:
- Subscribe A, B, C to topic "daily-deals"
- Send one message to topic "daily-deals"
= 1 API call, FCM delivers to all subscribers

Topics are ideal for broadcasts — news alerts, promotional announcements, app update notices — where the same message goes to a large group.

Subscribing Users to a Topic

Subscription happens server-side using the Admin SDK (you cannot subscribe from client code):

// Cloud Function or server script
const admin = require("firebase-admin");
admin.initializeApp();

async function subscribeToTopic(tokens, topic) {
  const response = await admin.messaging().subscribeToTopic(tokens, topic);
  console.log("Subscribed:", response.successCount, "devices");
  console.log("Failed:", response.failureCount, "devices");
  return response;
}

// Subscribe a user's device when they enable "sports" notifications
const userToken = "user-device-fcm-token";
await subscribeToTopic([userToken], "sports-news");

Unsubscribing from a Topic

async function unsubscribeFromTopic(tokens, topic) {
  const response = await admin.messaging().unsubscribeFromTopic(tokens, topic);
  console.log("Unsubscribed:", response.successCount, "devices");
}

await unsubscribeFromTopic([userToken], "sports-news");

Sending a Message to a Topic

async function sendTopicNotification(topic, title, body, data = {}) {
  const message = {
    notification: { title, body },
    data,
    topic   // topic name (no "/topics/" prefix needed for Admin SDK)
  };

  const messageId = await admin.messaging().send(message);
  console.log("Topic message sent:", messageId);
}

// Send to all subscribers of "sports-news"
await sendTopicNotification(
  "sports-news",
  "Match Alert",
  "India vs Australia — Live now!",
  { match_id: "ind-aus-2026", type: "cricket" }
);

Topic Naming Rules

  • Use only letters, numbers, hyphens, underscores, and periods
  • Maximum 900 characters
  • Case-sensitive: Sports-News and sports-news are different topics
  • Use consistent lowercase naming: sports-news, order-updates, promo-alerts

Combining Topics with Conditions

Send to users subscribed to one topic but not another, or to any of multiple topics, using condition expressions:

// Send to users subscribed to BOTH cricket AND india-team
const message = {
  notification: {
    title: "Team India wins!",
    body: "India beat Australia by 50 runs."
  },
  condition: "'cricket' in topics && 'india-team' in topics"
};

await admin.messaging().send(message);

// Send to users subscribed to cricket OR football
const message2 = {
  notification: {
    title: "Live Sports Alert",
    body: "Multiple matches happening now!"
  },
  condition: "'cricket' in topics || 'football' in topics"
};

await admin.messaging().send(message2);

Conditions support up to 5 topics combined with AND (&&) and OR (||) operators.

Managing Topic Subscriptions in Your App

A common pattern stores each user's notification preferences in Firestore and syncs them to FCM topics via a Cloud Function:

// When user toggles "Cricket notifications" in app settings
async function updateNotificationPreference(userId, topic, enabled) {
  const db = admin.firestore();
  await db.collection("users").doc(userId).update({
    [`notification_prefs.${topic}`]: enabled
  });
  // A Firestore trigger function handles subscribing/unsubscribing
}

// Cloud Function triggered by user settings change
exports.syncTopicSubscriptions = onDocumentUpdated(
  "users/{userId}",
  async (event) => {
    const before = event.data.before.data();
    const after = event.data.after.data();
    const userId = event.params.userId;

    // Get user's FCM tokens
    const tokensSnap = await admin.firestore()
      .collection("users").doc(userId).collection("fcm_tokens").get();
    const tokens = tokensSnap.docs.map((d) => d.data().token);
    if (tokens.length === 0) return;

    // Check which topics changed
    const prefsBefore = before.notification_prefs || {};
    const prefsAfter = after.notification_prefs || {};

    for (const topic of Object.keys(prefsAfter)) {
      if (prefsBefore[topic] !== prefsAfter[topic]) {
        if (prefsAfter[topic]) {
          await admin.messaging().subscribeToTopic(tokens, topic);
        } else {
          await admin.messaging().unsubscribeFromTopic(tokens, topic);
        }
      }
    }
  }
);

Key Takeaway

Topic messaging broadcasts one notification to all subscribers of a named topic with a single API call. Manage subscriptions server-side with the Admin SDK using subscribeToTopic and unsubscribeFromTopic. Use condition expressions to target combinations of topics. Store user notification preferences in Firestore and sync changes to FCM topic subscriptions via Cloud Function triggers.

Leave a Comment

Your email address will not be published. Required fields are marked *