DEV Community

Sujit M
Sujit M

Posted on • Edited on

Using Firebase Cloud Messaging (FCM) with React for Real-Time Notifications

Note: This guide is part of a public GitHub repository that you can refer to if you encounter any issues while implementing the notification system. Feel free to check it out for the full code and additional resources.
Repository: Repo

Integration with React

This is quite simple and straight forward.

I believe you do have the project ready if not then create using vite

We are using a react with typescript

npm create vite@latest my-vue-app --template react-ts
Enter fullscreen mode Exit fullscreen mode

To work with notification you need a device token APN token.(App registration on specific device) for that we need to convert your app into a PWA (Progressive Web App).

What is PWA?

At a high level, a PWA consists of a web application manifest to give the browser information about your app, and a service worker to manage the offline experience.

Lets add PWA Support

npm install vite-plugin-pwa --save-dev
Enter fullscreen mode Exit fullscreen mode

Refer Vite PWA for more info.

Now, open firebase console and set up a new project.

  • Navigate to project Settings firebase setting page
  • Locate Your apps
  • Add a new app by clicking on Add app

Firebase add app

You can select any environment but in our case we will choose web

  • Select web
  • Register your app

Remember to enable hosting as well

Once you finish the process you will receive the file and instructions.

Now we will create a notification modal.

To create a notification modal, let's install Bootstrap.

npm install bootstrap react-bootstrap
Enter fullscreen mode Exit fullscreen mode

Open App.tsx and replace with below code.

import "./App.css";
import { useState } from "react";
import { Button, Toast } from "react-bootstrap";
import "bootstrap/dist/css/bootstrap.min.css";

function App() {
    const [show, setShow] = useState(false);

    return (
        <div className="App">
            <Toast
                onClose={() => setShow(false)}
                show={show}
                delay={3000}
                autohide
                animation
                style={{
                    position: "absolute",
                    top: 20,
                    right: 20,
                }}
            >
                <Toast.Header>
                    <img src="holder.js/20x20?text=%20" className="rounded mr-2" alt="" />
                    <strong className="mr-auto">Notification</strong>
                    <small>5 mins ago</small>
                </Toast.Header>
                <Toast.Body>This will give us the Notification details</Toast.Body>
            </Toast>
            <header className="App-header">
                <Button onClick={() => setShow(true)}>Show Toast</Button>
            </header>
        </div>
    );
}

export default App;


Enter fullscreen mode Exit fullscreen mode

This will create a bootstrap toaster to display

Lets add firebase JS SDK

npm i firebase
Enter fullscreen mode Exit fullscreen mode

Now, create a new file in src directory firebase.js and add below code

import { initializeApp } from 'firebase/app';
import { getMessaging, getToken, onMessage } from "firebase/messaging";


const firebaseConfig = {
    apiKey: API_KEY,
    authDomain: AUTH_DOMAIN,
    projectId: PROJECT_ID,
    storageBucket: STORAGE_BUCKET,
    messagingSenderId: MESSAGING_SENDER_ID,
    appId: APP_ID,
    measurementId: MEASUREMENT_ID
};

const app = initializeApp(firebaseConfig);
const analytics = getAnalytics(app); //Comment this out
Enter fullscreen mode Exit fullscreen mode

Import firebase.js in your App.tsx

import "./firebase.js"
Enter fullscreen mode Exit fullscreen mode

Create a new file in public directory called firebase-messaging-sw.js and keep it empty for now

Start your react application

npm run dev
Enter fullscreen mode Exit fullscreen mode

This is how your screen will look like

Landing screen

Generate a token

go to firebase.js and create new function which will request a permission from a user

const messaging = getMessaging(app);


export const getTokens = async (setTokenFound) => {
//VAPID_KEY is the Web push certificates key pair
    return getToken(messaging, {vapidKey: VAPID_KEY }).then((currentToken) => {
        if (currentToken) {
            console.log('current token for client: ', currentToken);
            setTokenFound(true);
            // Track the token -> client mapping, by sending to backend server
            // show on the UI that permission is secured
        } else {
            console.log('No registration token available. Request permission to generate one.');
            setTokenFound(false);
            // shows on the UI that permission is required 
        }
    }).catch((err) => {
    console.log('An error occurred while retrieving token. ', err);
    // catch error while creating client token
});
}
Enter fullscreen mode Exit fullscreen mode

Generate VAPID_KEY

head back to the firebase console

  • Open Project Settings
  • Navigate to tab Cloud Messaging
  • Locate Web configuration Web Configuration at Firebase console
  • Select Web push certificate
  • Generate Key pair

Update vapidKey in firebase.js file to newly generated key.

What is VAPID?

The first is to restrict the validity of a subscription to a specific application server (so, by using VAPID, only your server will be able to send notifications to a subscriber).

The second is to add more information to the push notification, so that the push service operator knows who is sending the notifications. If something is going wrong with your notifications, the operator knows who you are and can contact you. Moreover, they can offer you some kind of interface to monitor your push notifications.

Now back to App.tsx and add the below code

import {getTokens} from './firebase'

// Inside a App function Just to be sure 😅
const [isTokenFound, setTokenFound] = useState(false);
getTokens(setTokenFound);
Enter fullscreen mode Exit fullscreen mode

Now open you devtool F12 and check console, you will have token if not there are might be error saying

  • Permission denied.

Ok this is the part is bit interesting you can manually unable the notification allow from i button before URL

Allow Notification Permission

But the interesting part is you can change your localhost:3000 to 127.0.0.1:3000 and it will ask you for a permission on chrome but both will work on firefox

Note - if you are using IPV6 then 127.0.0.1 will not work

Permission Request from Browser

  • The operation is unsecure

then the file you created. in public folder is not correct

check if the files has correct name as firebase-messaging-sw.js and it should be empty for now.

Perfect All seems working till this point and you might have a token as well but now we want to see the notification from the server

go to firebase-messaging-sw.js and copy below code

// Scripts for firebase and firebase messaging
importScripts('https://www.gstatic.com/firebasejs/8.2.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/8.2.0/firebase-messaging.js');

// Initialize the Firebase app in the service worker by passing the generated config
const firebaseConfig = {
    apiKey: API_KEY,
    authDomain: AUTH_DOMAIN,
    projectId: PROJECT_ID,
    storageBucket: STORAGE_BUCKET,
    messagingSenderId: MESSAGING_SENDER_ID,
    appId: APP_ID,
    measurementId: MEASUREMENT_ID
};

firebase.initializeApp(firebaseConfig);

// Retrieve firebase messaging
const messaging = firebase.messaging();

messaging.onBackgroundMessage(function(payload) {
  console.log('Received background message ', payload);
 // Customize notification here
  const notificationTitle = payload.notification.title;
  const notificationOptions = {
    body: payload.notification.body,
  };

  self.registration.showNotification(notificationTitle,
    notificationOptions);
});
Enter fullscreen mode Exit fullscreen mode

Now go to src->firebase.js and paste a listener function

export const onMessageListener = () =>
  new Promise((resolve) => {
    onMessage(messaging, (payload) => {
      console.log("payload", payload)
      resolve(payload);
    });
  });
Enter fullscreen mode Exit fullscreen mode

back to App.tsx and add use the newly created listener

import {getTokens, onMessageListener} from './firebase'

// Inside APP function
onMessageListener().then(payload=>{
  console.log(payload)
  setShow(true)
}).catch(err=>console.log(err))
Enter fullscreen mode Exit fullscreen mode

Okay, there is one thing need to receive our first message is we have to host this repo, Since firebase does not allow to send messages on http and it needs a secure channel https

Lets use firebase hosting

Install firebase tools

npm install -g firebase-tools
Enter fullscreen mode Exit fullscreen mode
firebase login
Enter fullscreen mode Exit fullscreen mode

This will prompt you to login to your google account or the account you used to create above project

firebase init
Enter fullscreen mode Exit fullscreen mode
  • use space bar to select Initial option to choose
  • Select Use an existing project
  • Select the project that you created from google console
  • Choose the options from below images Default firebase options

Now lets deploy
Verify things before you deploy.

  • Check your firebase.json and make sure deploy directory is mentioned correctly
{
    "hosting": {
        "public": "dist", // Change dist to your build directory
        "ignore": ["firebase.json", "**/.*", "**/node_modules/**"]
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Build your project
npm run build
Enter fullscreen mode Exit fullscreen mode

Lets deploy

firebase deploy
Enter fullscreen mode Exit fullscreen mode

All good, Awesome! we are ready to receive our first message.

  • Open firebase console
  • Navigate to all products from left menu
  • Find Cloud Messaging
  • Once you open Cloud Messaging

Cloud Messaging Dashboard

  • Create your first Campaign
  • Select Firebase Notification messages firebase notification console

Provide the required details and click on Send Test Message it will show a modal with asking for FCM Registration Token Like this

Asking FCM Token

Here you add the token from your web console that we just generated. This is your device token where firebase will send the notification.

Note- Notification will not show the same text as we have entered in firebase since we have not configured for demo purpose.

This is the front end part for the backend part i will create part 2 post which will cover server side notifications using firebase-admin and also subscriptions

Reminder: If you get stuck during the process of creating the notification system, you can always refer to this public GitHub repository. It's a great reference to guide you through the steps.
Repository: Repo

Hope it was useful.

Happy learning.

Top comments (3)

Collapse
 
ntduycs profile image
Duy Nguyen Thanh

Thanks for your sharing

Collapse
 
iamsujit profile image
Sujit M

You can check it out updated version.

Collapse
 
ishanjirety profile image
Ishan jirety

Deep explanation, Amazing !