Web-Based Notifications with Firebase: A Comprehensive Guide
Published: 2024-02-03 06:55:56

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:

- Firebase Account: Create a Firebase account if you don’t have one already. Set up a new project in the Firebase Console.
- Node.js and npm: Ensure Node.js and npm are installed on your development machine.
- 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.


![send test notification with firebase console](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ivuyd2piwii3f1bl4gvu.gif)