FCM Push notifications arrive twice if the browser is in background
Asked Answered
B

5

7

I've set up a simple push notification site, the notifications arrive okay if the browser is in foreground.

The problem begins if the browser is in background: the notification arrives twice, one styled with image and other settings set and the other has only title and body message.

Content of the service worker:

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

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

const messaging = firebase.messaging();

messaging.setBackgroundMessageHandler(function(payload) {
    console.log('[firebase-messaging-sw.js] Received background message ', 
    return null;
});

self.addEventListener('install', function (event) {
    event.waitUntil(skipWaiting());
});

self.addEventListener('activate', function (event) {
    event.waitUntil(clients.claim());
});

self.addEventListener('push', function (event) {
    var pushData = event.data.json();
    try {
        var notificationData = pushData.data;
        notificationData.data = JSON.parse(notificationData.data);
        console.log(notificationData);
        self.registration.showNotification(pushData.notification.title, notificationData);
    }
    catch (err) {
        console.log('Push error happened: ', err);
    }
});

Client side js:

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

messaging.onMessage(function (payload) {
    console.log("notification recieved");
    return null;
});

self.addEventListener('push', function (event) {
    console.log("window push stuff");
    return null;
});

Thanks!

Basaltware answered 11/10, 2017 at 13:57 Comment(0)
B
5

The problem can be solved with adding this line to the messaging.setBackgroundMessageHandler event:

self.registration.hideNotification();

This way, the default notification won't show and you have to show your notification in the self.addEventListener event.

Basaltware answered 16/10, 2017 at 6:57 Comment(4)
Weird, didn't work for me. Still shows up default notification and then runs on "push" function.Linctus
Oh, okay, I know why it didn't work for me!! github.com/firebase/quickstart-js/issues/71Linctus
@mzvarik I have the same problem! could you please tell how did you solved it? the hideNotification() didn't worked for me!Joshia
@Joshia I changed the POST request, read carefully this comment: github.com/firebase/quickstart-js/issues/…Linctus
D
9

Simplest way to 100% avoid multiple notifications is adding "tag", eg.:

var options = {
    body: "text",
    tag: "notification-1"
};
self.registration.showNotification("title", options)
Dunlin answered 11/6, 2018 at 20:53 Comment(1)
@judasane It uniquely identifies the message, so it pops up only once, NOT several times.Linctus
B
5

The problem can be solved with adding this line to the messaging.setBackgroundMessageHandler event:

self.registration.hideNotification();

This way, the default notification won't show and you have to show your notification in the self.addEventListener event.

Basaltware answered 16/10, 2017 at 6:57 Comment(4)
Weird, didn't work for me. Still shows up default notification and then runs on "push" function.Linctus
Oh, okay, I know why it didn't work for me!! github.com/firebase/quickstart-js/issues/71Linctus
@mzvarik I have the same problem! could you please tell how did you solved it? the hideNotification() didn't worked for me!Joshia
@Joshia I changed the POST request, read carefully this comment: github.com/firebase/quickstart-js/issues/…Linctus
J
5

It took for me around two weeks for me to understand and solve this issue. Hope that will save time for other people:

Firebase supports two types of push notifications:

  1. Display notifications that FCM SDK handles automatically Data
  2. Data messages, which are handled by the client app

Firebase cloud messaging UI has many advantages like advanced targeting by countries, devices, languages, and more. But it allows sending URLs only inside the data custom field.

Message sent from Firebase Console UI looks this way:

 {
    notification: {
      title: "New Test",
      body: "This is test",
    },
    data: {
      url: 'someurl.com',
    },
  };

The notification comes twice when the service worker handles it and a second time when FCM SDK automatically does it.

I didn't found a way to disable auto handling of notification and in the frontend and used Firebase Functions to send it only as data message:

 {
    data: {
      title: "New Test",
      body: "This is test",
      url: 'someurl.com',
    },
  };

So, if you want to pass custom URL to push notification, you will need to send it from your own server or using firebase functions.

Jumbala answered 12/6, 2021 at 9:35 Comment(1)
This is exactly the right answer. I had to stare at the chart on the top of the documentation page for a while to get it but it makes total sense now. Unless it's a data message it will be automatically be shown and calling registration.showNotification will show another. firebase.google.com/docs/cloud-messaging/js/receiveSelfsealing
C
4

This is how I get Firebase Cloud Messaging Notifications to work in Progresse Web Apps on Android Devices with those requirements:

  1. Push notifications should only appear once in the status bar as well
  2. The number of notifications should be highlighted at on the PWA app icon
  3. The notification in the status bar should contain:
  • A small badge with the app icon
  • The actual app icon
  • A noticiation title
  • A notification body
  • Open the PWA on tap

Push Notification in Status Bar Badge on App Icon

firebase-messaging.sw.js

Don't add any cdoe or onBackgroundMessage() handler to this file. My file is nothing more but

//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/8.3.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/8.3.0/firebase-messaging.js');

// Initialize the Firebase app in the service worker by passing in
// your app's Firebase config object.
// https://firebase.google.com/docs/web/setup#config-object
firebase.initializeApp({
  apiKey: 'api-key',
  authDomain: 'project-id.firebaseapp.com',
  databaseURL: 'https://project-id.firebaseio.com',
  projectId: 'project-id',
  storageBucket: 'project-id.appspot.com',
  messagingSenderId: 'sender-id',
  appId: 'app-id',
  measurementId: 'G-measurement-id',
});

// Retrieve an instance of Firebase Messaging so that it can handle background
// messages.
if (firebase.messaging.isSupported()) {
  const messaging = !firebase.apps.length
    ? firebase.initializeApp(firebaseConfig).messaging()
    : firebase.app().messaging();

Server side job to send notifications

The content and structure of the messaging payload is key. Put your notification object into a webpush object. Do not add a data object in order to avoid dubplicate notifications with incomplete content.

Make sure your badge is 24x24px png that contains only white content on a transparent background.

  var message = {
    webpush: {
      notification: {
        title: "Let's Join App",                          // Your message title
        body: messageBody,                                // Your message body
        icon: "./img/icons/android-chrome-192x192.png",   // Your App icon, up to 512x512px, any color
        badge: "./img/icons/badge.png",                   // Your app badge, 24x24px, white content on transparent background
      },
      fcmOptions: {
        link: "https://www.letsjoin.app",                 // Your Link
      },
    },
    token,
  };

  // Send a message to the device corresponding to the provided
  // registration token.
  await admin
    .messaging()
    .send(message)
    .then((response) => {
      // Response is a message ID string.
      console.log("Successfully sent message");
    })
    .catch((error) => {
      console.log("Error sending message:", error.errorInfo.message);
    });
};
Corabella answered 18/3, 2021 at 9:40 Comment(2)
Does this work the same when sending notifications to a topic?Leet
Can you give us your full firebase-messaging.sw.js code ?Polymeric
B
0

After several attempts, I think I found a workaround. The problem seems to be the self or global window that triggers twice notification. Simply update your messaging.onBackgroundMessage to this:

messaging.onBackgroundMessage((payload) => {
  const notificationTitle = payload.notification.title;
  const notificationOptions = {
    body: payload.notification.body,
    icon: payload.notification.image,
  };
  navigator.serviceWorker.ready.then(function (registration) {
    registration.showNotification(notificationTitle, notificationOptions);
  });
});
Brawley answered 24/7, 2024 at 5:45 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.