Send Messages to Multiple Devices

Firebase Cloud Messaging provides these two ways to target a message to multiple devices:

  • Topic messaging, which allows you to send a message to multiple devices that have opted in to a particular topic.
  • Device group messaging, which allows you to send a message to multiple devices that belong to a group you define.

This tutorial focuses on sending topic messages from your app server using the HTTP or XMPP protocols for FCM, and receiving and handling them in a web app. We'll cover message handling for both backgrounded and foregrounded apps.

About topic messaging

Based on the publish/subscribe model, FCM topic messaging allows you to send a message to multiple devices that have opted in to a particular topic. You compose topic messages as needed, and FCM handles routing and delivering the message reliably to the right devices.

For example, users of a local weather forecasting app could opt in to a "severe weather alerts" topic and receive notifications of storms threatening specified areas. Users of a sports app could subscribe to automatic updates in live game scores for their favorite teams.

Some things to keep in mind about topics:

  • Topic messaging supports unlimited topics and subscriptions for each app.
  • Currently, topic message payload is limited to 2KB.
  • Topic messaging is best suited for content such as news, weather, or other publicly available information.
  • Topic messages are optimized for throughput rather than latency. For fast, secure delivery to single devices or small groups of devices, target messages to registration tokens, not topics.
  • If you need to send messages to multiple devices per user, consider device group messaging for those use cases.

About device group messaging

With device group messaging, you can send a single message to multiple instances of an app running on devices belonging to a group. Typically, "group" refers a set of different devices that belong to a single user. All devices in a group share a common notification key, which is the token that FCM uses to fan out messages to all devices in the group.

You can use device group messaging with the Admin SDKs, or by implementing the XMPP or HTTP protocols on your app server. The maximum number of members allowed for a notification key is 20.

Set up the SDK

This section may cover steps you already completed if you have set up a JavaScript client app for FCM or worked through the steps to receive messages.

Add Firebase to your JavaScript project

If you haven't already, add Firebase to your JavaScript project.

Configure the browser to receive messages

You'll need to add a web app manifest that specifies the gcm_sender_id, a hard-coded value indicating that FCM is authorized to send messages to this app. If your app already has a manifest.json configuration file, make sure to add the browser sender ID exactly as shown (do not change the value):

{
  "//": "Some browsers will use this to enable push notifications.",
  "//": "It is the same for all projects, this is not your project's sender ID",
  "gcm_sender_id": "103953800507"
}

Retrieve a messaging object

// Retrieve Firebase Messaging object.
const messaging = firebase.messaging();

Request permission to receive notifications

The method messaging.requestPermission() displays a consent dialog to let users grant your app permission to receive notifications in the browser. If permission is denied, FCM registration token requests result in an error.

messaging.requestPermission()
.then(function() {
  console.log('Notification permission granted.');
  // TODO(developer): Retrieve an Instance ID token for use with FCM.
  // ...
})
.catch(function(err) {
  console.log('Unable to get permission to notify.', err);
});

Access the registration token

This section describes how to retrieve the registration token for an app instance, and how to monitor token refresh events. Because the token could be rotated after initial startup, you should monitor token refresh and always retrieve the latest updated registration token.

The registration token may change when:

  • The web app deletes the registration token.
  • The user clears browser data. In this case, call getToken to retrieve the new token.

Retrieve the current registration token

When you need to retrieve the current token, call getToken. This method returns null when permission has not been granted. Otherwise, it returns a token or rejects the promise due to an error.

  // Get Instance ID token. Initially this makes a network call, once retrieved
  // subsequent calls to getToken will return from cache.
  messaging.getToken()
  .then(function(currentToken) {
    if (currentToken) {
      sendTokenToServer(currentToken);
      updateUIForPushEnabled(currentToken);
    } else {
      // Show permission request.
      console.log('No Instance ID token available. Request permission to generate one.');
      // Show permission UI.
      updateUIForPushPermissionRequired();
      setTokenSentToServer(false);
    }
  })
  .catch(function(err) {
    console.log('An error occurred while retrieving token. ', err);
    showToken('Error retrieving Instance ID token. ', err);
    setTokenSentToServer(false);
  });
}

Monitor token refresh

The onTokenRefreshcallback fires whenever a new token is generated, so calling getToken in its context ensures that you are accessing a current, available registration token.

// Callback fired if Instance ID token is updated.
messaging.onTokenRefresh(function() {
  messaging.getToken()
  .then(function(refreshedToken) {
    console.log('Token refreshed.');
    // Indicate that the new Instance ID token has not yet been sent to the
    // app server.
    setTokenSentToServer(false);
    // Send Instance ID token to app server.
    sendTokenToServer(refreshedToken);
    // ...
  })
  .catch(function(err) {
    console.log('Unable to retrieve refreshed token ', err);
    showToken('Unable to retrieve refreshed token ', err);
  });
});

After you've obtained the token, send it to your app server and store it using your preferred method. You can use the Instance ID server API to get information about subscriptions

Subscribe the client app to a topic

Given a registration token and a topic name, you can create a mapping using the Google Instance ID server API. Call the Instance ID service at this endpoint, providing the app instance's registration token and the topic name:

 https://iid.googleapis.com/iid/v1/REGISTRATION_TOKEN/rel/topics/TOPIC_NAME

To subscribe an app instance to a topic named "movies," for example, send the following POST request to the endpoint, adding your server API key in the authorizaton header as shown:

https://iid.googleapis.com/iid/v1/nKctODamlM4:CKrh_PC8kIb7O...clJONHoA/rel/topics/movies
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA

A successful request returns HTTP 200 OK. For more information about error responses and about how to send batch requests, see Create relationship maps for app instances

Receive and handle topic messages

The behavior of messages differs depending on whether the page is in the foreground (has focus), or in the background, hidden behind other tabs, or completely closed. In all cases the page must handle the onMessage callback, but in background cases you'll also need to configure the display notification to allow the user to bring your web app into the foreground.

Handle messages when your web app is in the foreground

In order to receive the onMessage event, your app must define the Firebase messaging service worker in firebase-messaging-sw.js. Alternatively, you can specify an existing service worker with useServiceWorker.

// Give the service worker access to Firebase Messaging.
// Note that you can only use Firebase Messaging here, other Firebase libraries
// are not available in the service worker.
importScripts('https://www.gstatic.com/firebasejs/3.9.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/3.9.0/firebase-messaging.js');

// Initialize the Firebase app in the service worker by passing in the
// messagingSenderId.
firebase.initializeApp({
  'messagingSenderId': 'YOUR-SENDER-ID'
});

// Retrieve an instance of Firebase Messaging so that it can handle background
// messages.
const messaging = firebase.messaging();

When your app is in the foreground (the user is currently viewing your web page), you can receive data and notification payloads directly in the page.

// Handle incoming messages. Called when:
// - a message is received while the app has focus
// - the user clicks on an app notification created by a sevice worker
//   `messaging.setBackgroundMessageHandler` handler.
messaging.onMessage(function(payload) {
  console.log("Message received. ", payload);
  // ...
});

Handle messages when your web app is in the background

All messages received while the app is in the background trigger a display notification in the browser. You can specify options for this notification, such as title or click action, either in the send request from your app server, or using service worker logic on the client.

Setting notification options in the send request

For notification messages sent from the app server, the FCM JavaScript API supports the click_action key. Typically this is set to a page in your web app, so that when a user clicks on the notification, your app is brought to the foreground.

https://fcm.googleapis.com/fcm/send
Content-Type: application/json
Authorization: key=AIzaSyC...akjgSX0e4

{ "notification": {
    "title": "Background Message Title",
    "body": "Background message body",
    "click_action" : "https://dummypage.com"
  },

  "to" : "/topics/matchday"

}

Because data messages don't support click_action, you are recommended to add a notification payload to all data messages. Alternatively, you can handle notifications using the service worker.

For an explanation of the difference between notification and data messages, see Message types.

Setting notification options in the service worker

For both notification messages and data messages, you can set notification options in the service worker. First, initialize your app in the service worker:

// Give the service worker access to Firebase Messaging.
// Note that you can only use Firebase Messaging here, other Firebase libraries
// are not available in the service worker.
importScripts('https://www.gstatic.com/firebasejs/3.9.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/3.9.0/firebase-messaging.js');

// Initialize the Firebase app in the service worker by passing in the
// messagingSenderId.
firebase.initializeApp({
  'messagingSenderId': 'YOUR-SENDER-ID'
});

// Retrieve an instance of Firebase Messaging so that it can handle background
// messages.
const messaging = firebase.messaging();

To set options, call setBackgroundMessageHandler in firebase-messaging-sw.js. In this example, we set options for title, body, icon, and click action.

messaging.setBackgroundMessageHandler(function(payload) {
  console.log('[firebase-messaging-sw.js] Received background message ', payload);
  // Customize notification here
  const notificationTitle = 'Background Message Title';
  const notificationOptions = {
    body: 'Background Message body.',
    icon: '/firebase-logo.png'
  };

  return self.registration.showNotification(notificationTitle,
      notificationOptions);
});

Build send requests

From the server side, sending a notification message to an FCM topic is very similar to sending messages to an individual device. The app server sets the to key with a value like /topics/yourTopic, and adds a notification payload:

{
   "to" : "/topics/matchday",

   "notification" : {
     "title": "Portugal vs. Denmark",
     "text": "5 to 1"
   }
}

For more information about sending to combinations of multiple topics and sending data messages, see send messages to topics.

Send feedback about...

Need help? Visit our support page.