Firebase Messaging for Web app in React with Notification sound
When you have a web application and want your users to get a browser notification whenever the backend state changes it becomes a little tricky since you are no longer monitoring directly from the frontend.
In these cases, you can use the backend to trigger firebase messaging when an event occurs and use the below frontend configuration to receive notification both when the application is focused in the browser or the application browser tab is minimized/not focused.
Prerequisite
- Install Firebase
npm i firebase
- Get firebase configuration from your firebase app console:
{
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',
}
- Generate a key pair(vapid key) to get token for messaging
Firebase Messaging in React App
Add service worker in react app- Background Messaging:
Why: You need to add the firebase service worker in the react app to receive the background notification. Whenever your web application browser tab is not focused, firebase will use the background messaging function to trigger notifications.
In the public directory of the react app, add firebase-messaging-sw.js:
Note: Windows global object will not be accessible here.
Note: You don't have to manually register this service worker. It works in localhost as well- so you won't have trouble with testing.
importScripts('https://www.gstatic.com/firebasejs/9.2.0/firebase-app-compat.js'); importScripts('https://www.gstatic.com/firebasejs/9.2.0/firebase-messaging-compat.js');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',
});const messaging = firebase.messaging();messaging.onBackgroundMessage(function(payload) { //use BroadcastChannel for notification
const channel = new BroadcastChannel('notification_channel_name');channel.postMessage({ key: payload });});
Set Foreground Messaging:
You can set the foreground messaging for the notification received when the web apps browser tab is focused.
You can configure foreground messaging in the component to which the notifications are related or in a component that loads when a user opens the app so the app can set the messaging token whenever the token is updated.
Foreground configuration: I set it in the routers component — App.js
import { initializeApp } from "firebase/app";
import { getMessaging, onMessage, getToken } from "firebase/messaging";//Add this in relevant component
const app = 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',
});const messaging = getMessaging(app);//save firebase token locally
const FirebaseToken = localStorage?.FirebaseToken;//notification permission
const getNotification = () => {
Notification.requestPermission();if (!("Notification" in window)) {
} else {
Notification.requestPermission();
}getFirebaseToken();//set token};const getFirebaseToken=()=>{
getToken(messaging, {
vapidKey:"YOUR_VAPID_KEY"
}).then((currentToken) => {
if (currentToken) {
if (FirebaseToken !== currentToken) {
localStorage.setItem("FirebaseToken", currentToken);
//also save the token in your apps backend to send the message to all those saved deviceIDs
}
}else {
getNotification();//ask for permission
}
}).catch((err) => {});}//foreground message
onMessage(messaging, (payload) => {
if (payload) {
showNotification(payload);
}
});//BroadcastChannel to recieve background messaging
const channel = new BroadcastChannel("notification_channel_name");channel.onmessage = (event) => {
showNotification(event.data.key)
};const showNotification=(body)=>{
if (body) {
//notification sound
let sound = new Audio(n5);
sound.play();//notification body
const options = {
body: body.notification.body,
icon: "icon.png",
vibrate: true,//vibrate will work only on the mobile device
};let notification = new Notification(body.notification.title, options);notification.onclick = function (event) {
event.preventDefault();
window.open("LINK_YOU_WANT_USER_TO_OPEN", "_blank");
};
}
}
Mostly you will see that developers are using the service workers' notification. The only thing wrong with it is that you won't be able to add sound to the notification.
If the notifications you are sending are important and need an immediate action of your user — You must add a notification sound which you will have to play independently as shown in the showNotification function.
What to do next
Make sure to delete the token on logout or just get a new firebase token and do not save it, this way when your app is closed/logged out the browser won't receive notifications.