Web-Based Notifications with Firebase: A Comprehensive Guide

Yash NerkarYash Nerkar
Feb 05, 2024·
5 min read

In the era of web development, user engagement plays a crucial role. One effective way to enhance user experience in web-apps is through web-based notifications. Firebase, a mobile and web application development platform, provides a robust solution for implementing push notifications seamlessly.

Overview

Web-based notifications use the capabilities of service workers to deliver real-time updates to users, even when the application is not open. Firebase Cloud Messaging (FCM) is the go-to service for implementing push notifications.

Prerequisites

Before implementation, make sure you have the following prerequisites:

  1. Firebase Account: Create a Firebase account if you don't have one already. Set up a new project in the Firebase Console.

  2. Node.js and npm: Ensure Node.js and npm are installed on your development machine.

  3. React App: Set up a React application using Create React App or any other preferred method.

Server-Side (Node.js)

1. Install Firebase Admin SDK

To enable server-side communication with FCM, you need to install the Firebase Admin SDK. Run the following command in your server-side project:

npm install firebase-admin

2. Initialize Firebase Admin

In your server-side code (e.g., server.js), initialize Firebase Admin using your Firebase project credentials:

const admin = require('firebase-admin');

const serviceAccount = require('path/to/your/firebase-credentials.json');

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
});

3. Create a Function for Sending Notifications

Now, create a function that sends notifications to the FCM token:

export async function sendPushNotification(deviceToken: string, title: string, body: string, data: { url: string }) {
  return new Promise((resolve, reject) => {
    try {
      const message: admin.messaging.Message = {
        notification: {
          title: title,
          body: body,
        },
        token: deviceToken,
        data
      };

      admin.messaging().send(message)
        .then((response: any) => {
          console.log("response send to", response);
          return resolve('Push notification sent');
        })
        .catch((error: any) => {
          console.log("error from index push", error);
          return reject('Error sending push notification');
        });
    } catch (error) {
      console.error("error from index push catch", error);
      throw error;
    }
  })
};

Client-Side (React)

1. Set Up Firebase in React

Install the Firebase package in your React project

npm install firebase

Initialize Firebase in your firebase.js file or other appropriate file.

import { initializeApp } from "firebase/app";
import {
  FIREBASE_APP_ID,
  FIREBASE_MEASUREMENT_ID,
  FIREBASE_PROJECT_ID,
  FIREBASE_STORAGE_BUCKET,
  FIREBASE_MESSAGING_SENDER_ID,
  FIREBASE_AUTH_DOMAIN,
  FIREBASE_API_KEY,
} from "../config/environment";

// Your web app's Firebase configuration

export const firebaseConfig = {
  apiKey: FIREBASE_API_KEY,
  authDomain: FIREBASE_AUTH_DOMAIN,
  projectId: FIREBASE_PROJECT_ID,
  storageBucket: FIREBASE_STORAGE_BUCKET,
  messagingSenderId: FIREBASE_MESSAGING_SENDER_ID,
  appId: FIREBASE_APP_ID,
  measurementId: FIREBASE_MEASUREMENT_ID,
};

export const app = initializeApp(firebaseConfig);

// by exporting you can use your app anywhere in the react app..

2. Request Notification Permission

Request permission from the user to receive notifications:

const requestPermission = async () => {
    const permission = await Notification.requestPermission();
    if (permission === "granted") {
      console.log("Notification permission granted.");
    } else if (permission === "denied") {
      console.log("Permission denied.");
    }
  };

To Get Device Token :

import { getMessaging, getToken } from "firebase/messaging";
import { app } from "../../../src/utils/firebase/firebase";
import { VAPID_KEY } from "../../../src/utils/config/environment";

const [deviceToken, setDeviceToken] = React.useState("");

React.useEffect(() => {
    if (
      "Notification" in window &&
      "serviceWorker" in navigator &&
      "PushManager" in window
    ) {
      requestPermission();
      const messaging = getMessaging(app);
      const getFCMToken = async () => {
        try {
          const token = await getToken(messaging, {
            vapidKey: VAPID_KEY,
          });
          if (token) {
            console.log("token", token);
            setDeviceToken(token);
          } else {
            console.log("No FCM token received.");
          }
        } catch (error) {
          console.error("Error getting FCM token:", error);
        }
      };
      getFCMToken();
    } else {
      console.log("FCM not supported");
    }
  }, []);
  • getMessaging : The getMessaging sets up FCM and returns an object for managing notifications, subscriptions, incoming messages, and device tokens.

  • getToken : The getToken method is used to retrieve the Firebase Cloud Messaging (FCM) token assigned to the current user.

  • VAPID_KEY : To retrive vapid_key :

    • Go to your Firebase project settings in the Firebase Console.

    • Find and click on the "Cloud Messaging" tab.

    • Look for Web Push Certificates or Web Configuration.

    • If a key is present, copy it. Otherwise, generate a new pair using the "Update Pair" or similar action.

  • The generated device token send to the backend to store in a database.

3. Setup Firebase-messaging-service worker

//firebase-messaging-sw.js
import firebaseConfig from "./firebase";


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

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

messaging.onBackgroundMessage((payload) => {
  console.log(  
    "[firebase-messaging-sw.js] Received background message ",
    payload
  );
  const notificationTitle = payload.notification.title;
  const notificationOptions = {
    body: payload.notification.body,
    icon: '/images/myna-logo.jpg',
  };

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

Note: This file should be stored in the public folder of your react or next js application, because Service workers are registered using a relative path , adding in public folder, the registration path would be simply./firebase-messaging-sw.js.

4. To Register firebase messaging service worker

React.useEffect(() => {
    if ("serviceWorker" in navigator) {
      navigator.serviceWorker
        .register("/firebase-messaging-sw.js")
        .then(function (registration) {
          console.log("Registration successful, scope is:", registration.scope);
        })
        .catch(function (err) {
          console.log("Service worker registration failed, error:", err);
        });
    }
  }, []);

After registering the service worker (to check the worker has registered or not, go to the service workers in the application inside the developer console). To test notifications, you can send them either from your server using the FCM token or directly from the Firebase console.

Navigate to the Firebase Console, click on the 'Messaging' tab on the left side, and then select 'Create your first campaign' to send a push notification, then you have to check on the Firebase Notification Message, so the below window will open up.

By clicking on send test message you have to add your FCM token in the pop up and then you can receive notifications in the background mode.

66
Subscribe to my newsletter

Read articles from Yash Nerkar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Yash Nerkar
Yash Nerkar

Web development has been my passion since the second year of college. Starting with HTML, CSS, and JavaScript, I progressed to backend development and view engines such as EJS and Handlebars. React JS was my next step, and I honed my skills during an internship as a frontend developer, where I used Figma wireframes to create websites. My coding journey continues with active participation in LeetCode and GFG. As the Technical Lead for CSI DMCE's core committee, I am actively involved in technical projects. I won an intracollege hackathon called HackOverflow and completed several Hacktoberfest challenges.