Firebase Push Notifications in React: A Complete Guide

Introduction

In this blog, we will see Firebase push notifications, focusing on their integration within React applications. We’ll cover the essentials of setting up and sending notifications, with ensuring cross-browser compatibility, including the often tricky Safari browser.

Prerequisites

Before proceeding, please ensure that you have the following prerequisites installed:

🔸 Basic Knowledge of React: Familiarity with React fundamentals is necessary as we will be implementing notifications in a React app.

🔸 Firebase Account: Access to Firebase, as we will be using Firebase services for push notifications.

🔸 Web Browser for Testing: Chrome, Firefox, and Safari for testing cross-browser compatibility.

What is Firebase Push Notification?

Firebase push notifications are a feature of Google’s Firebase Cloud Messaging (FCM), a free service that allows app developers to send notifications and messages to users across multiple platforms, including Android, iOS, and the web. These notifications are highly effective for personalized user engagement because they can be tailored and sent to individual users.

Let’s Start the Implementation Step by Step:

Create a React Application with the CRA Command:

Create a new React app with Create React App, a tool that creates a new React project with a reasonable default setup.

npx create-react-app auth-goal-fe
cd auth-goal-fe

Create and Setup the Firebase Project:

➡️ Go to the Firebase dashboard and after login create a new project by clicking on Add Project.

firebase-return-project
Fig: Firebase Demo Project

➡️ Then follow the Firebase project setup which is straightforward and guides you through the necessary steps
➡️ Once the project setup is done you will be redirected to your project dashboard
➡️ Then click on the settings. And go to the cloud messaging tab

Firebase-Cloud-Messaging
Fig: Firebase Cloud Messaging

➡️ Under this section, You should see an option “Generate Key Pair”. Click on this button. This action will create a unique pair of public and private keys that are essential for securely sending notifications to your web application. With your web push certificates in hand, you’re now ready to proceed with integrating push notifications into your React application.

Web-Push-Certificates
Fig: Web Push Certificates

Import Necessary Module in React Application:

npm i firebase react-toastify

Firebase: This package allows your application to interact seamlessly with Firebase services, including the push notification feature.

React-Toastify: A highly customizable and easy-to-use package for adding notifications, alerts, or toasts within your React application.

Initialize Firebase

➡️ Inside your source directory create firebase.json file
➡️ Then go to the firebase dashboard inside settings > general. Create a web app by clicking on the add app button. And copy all the configurations.
➡️ You can also initialize all these definitions in env and use them wherever you want. It depends on personal preference.

Firebase-Project-Settings
Fig: Firebase Project Settings

➡️ For configuration refer to the below code.

import { initializeApp } from "firebase/app";
import { getMessaging, getToken, onMessage } from "firebase/messaging";
import { toastMessage } from "./components/ToastMessage";
import { getAnalytics } from "firebase/analytics";
const firebaseConfig = {
apiKey: "********************",
authDomain: "********************",
projectId: "********************",
storageBucket: "********************",
messagingSenderId: "********************",
appId: "********************",
measurementId: "********************",
};

export const onMessageListener = () =>
new Promise((resolve) => {
onMessage(messaging, (payload) => {
resolve(payload);
});
});

initializeApp(firebaseConfig);
export const getMessagingToken = (setTokenFound) => {
return getToken(messaging, {
vapidKey:"unique_pair_of_public_and_private_keys ",
})
.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
});
};

const firebaseApp = initializeApp(firebaseConfig);
const analytics = getAnalytics(firebaseApp);
const messaging = getMessaging(firebaseApp);

Getting the Messaging Token

This function tries to obtain a messaging token, essential for sending Firebase push notifications to the client. If successful, it sets a flag (setTokenFound) indicating that the token is available. If the browser does not allow notification permission, this function first asks for notification permission and then generates the FCM (Firebase cloud messaging) token.

VapidKey:

The vapidKey used here is the unique key pair generated earlier in your Firebase project settings under the Web Push Certificates section. This key is essential for securing and authenticating communication between your web app and Firebase’s servers. By adding this key to your Firebase messaging setup, you create a trusted channel for sending and receiving Firebase push notifications, ensuring that these notifications come from your server and are securely delivered to the recipients.

Here We Have Some Scenarios to Understand:

If notification permission is not given then it will ask for permission suppose the user allows the permission then you will get the FCM token successfully.
If the user dont allow the permission and blocks it instead. In that case, you will not get the FCM token that is required for sending the notification.

Getting Notification (onMessageListener)

The onMessageListener function in your React app is crucial for managing real-time Firebase push notifications. When the app is active, it exports a promise that listens for incoming Firebase messages. When a message arrives, Firebase’s onMessage function is called, passing along the notification’s details (payload). This configuration ensures that any notifications sent while the app is in the foreground are received and processed immediately.

The payload, which contains information such as the title and body of the notification, is logged for debugging and then resolved, indicating the successful completion of this asynchronous operation. This function is important for the seamless and interactive user experience that keeps users engaged with real-time updates.

Upgrade Your App with Firebase Notifications! Hire developers now for Enhanced User Engagement

Foreground Notifications

Here we can simply handle the foreground notification in our app.js file inside the src folder.

Refer the Below Code:

import { useState } from "react";
import { getMessagingToken, onMessageListener } from "./firebase";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import { toastMessage } from "./components/ToastMessage";

function App() {
const [isTokenFound, setTokenFound] = useState(false);
getMessagingToken(setTokenFound);

onMessageListener()
.then((payload) => {
console.log(payload, "<<");
toast.success(
<div>
<p>{payload.data.title}</p>
<p style={{ marginTop: "4px" }}>{payload.data.body}</p>
</div>,
{
position: toast.POSITION.TOP_RIGHT,
}
);
})
.catch((err) => console.log("failed: ", err));

return (
<div className="App">
<ToastContainer
hideProgressBar={true}
newestOnTop={false}
limit={1}
autoClose={3000}
/>
<h1>
{isTokenFound && " Notification permission enabled 👍🏻 "}
{!isTokenFound && " Need notification permission ❗️ "}
</h1>
</div>
);
}

export default App;

In the code above, we utilize the onMessageListener function to handle foreground notifications within the App.js file, which serves as the root component of our React application. This function returns a promise, and we handle this promise in App.js to display Firebase push notification messages. To present these notifications in a user-friendly manner, we use the react-toastify library, which allows us to show elegant toast notifications.

We’re also using the previously defined getMessagingToken function in the provided snippet. This function is crucial in configuring Firebase push notification permissions. We first declare a state variable isTokenFound with React’s useState hook and initializing it to false. The function getMessagingToken is then called with the argument setTokenFound, which is a function to update the state.

We dynamically display messages in our UI based on the state of isTokenFound: if isTokenFound is true, it indicates that notification permissions have been granted, displaying “Notification permission enabled.” If isTokenFound is false, it indicates that the notification permission has not yet been obtained, displaying “Need notification permission”. This method effectively informs users in real time about the status of notification permissions.

Background Notification (ServiceWorker file)

Background notifications are messages received by a mobile or web application while it is not actively in use, which are typically delivered to the device’s notification centre for later user attention.

For getting background notification we need a service worker file that in present inside a public folder of the react project. Your service worfile name conversion should be firebase-messaging-sw.js.

For service Workers Refer to Below Code:

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

// Initialize the Firebase app in the service worker by passing the generated config
var firebaseConfig = {
apiKey: "***********",
authDomain: "***********",
projectId: "***********",
storageBucket: "***********",
messagingSenderId: "***********",
appId: "***********",
};

firebase.initializeApp(firebaseConfig);

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

messaging.onBackgroundMessage(function (payload) {
console.log("Received background message ", payload);
const notificationTitle = payload.notification.title;
const notificationOptions = {
body: payload.notification.body,
icon: "https://freeiconshop.com/wp-content/uploads/edd/notification-flat.png",
};

self.registration.showNotification(notificationTitle, notificationOptions);

self.addEventListener("notificationclick", function (event) {
console.log("clicked on notification", payload);
const notification = payload?.data;
event.notification.close();
event.waitUntil(clients.openWindow("/example.com"));
});
});

In our Firebase service worker script, first we import the Firebase app and messaging libraries required for Firebase push notification integration. The script uses firebase.initializeApp(firebaseConfig) to initialize Firebase with our project’s specific configuration details, establishing a connection to Firebase services. Then, with const messaging = firebase.messaging(), we create a Firebase messaging instance, which is required for handling push notifications. The core functionality is contained in messaging.onBackgroundMessage, which is called when a background notification is received.

This function processes the payload, which contains information such as the notification’s title and body, as well as possibly additional custom data. Using this information, we configure and display the notification via self.registration.showNotification(notificationTitle, notificationOptions), ensuring that users receive timely updates even when the web app is not active. A notificationclick event listener is also added to define actions when the notification is clicked. Clicking on the notification, such as opening a specific URL, increases user engagement.

Firebase Cloud Messaging on Safari for macOS

For receiving push notification in safari you just have to do some extra things.

Configure the Manifest File

{ "display": "standalone" } // or {"display": "fullscreen"}

🔸 Update your web application’s manifest.json file to ensure that your app can be added to the Home Screen on Safari. Set the “display” property to either “standalone” or “fullscreen”. This can be done by including a line like { “display”: “standalone” } or { “display”: “fullscreen” } in your manifest.json. This step is crucial for making your web app feel more like a native application on iOS devices, and it paves the way for smoother notification handling.

Initialize Firebase Cloud Messaging

// Example: wrapping permission request call inside a button click
const myButton = document.querySelector("button");
myButton.addEventListener("click", async () => {
let permission = await Notification.requestPermission();
if (permission === "granted") {
console.log("Notification permission granted. Requesting for token.");
let token = await messaging.getToken({
vapidKey: "<YOUR_PUBLIC_VAPID_KEY_HERE>",
});
// do something with the FCM token
} else {
console.log("Notification permission denied");
// Handle denied permission
}
});

🔶 With your app’s display settings configured, the next step is to initialize Firebase Cloud Messaging. This process involves requesting notification permission from the user and then obtaining the FCM token if permission is granted. You can wrap this in an interactive element, such as a button-click event.

Related read: Firebase Cloud Messaging Integration: Enabling Push Notifications in Spring Server

Here’s a basic outline of what the code would look like:

🔹 First, select a button element using const myButton = document.querySelector(“button”);.
🔹 Add an event listener to this button: myButton.addEventListener(“click”, async () => {…});.
🔹 Inside the event listener, request notification permission using let permission = await Notification.requestPermission();.
🔹 If the permission is granted (if (permission === “granted”)), log the success message and request the FCM token by calling messaging.getToken({ vapidKey: “<YOUR_PUBLIC_VAPID_KEY_HERE>” }).
🔹 Handle the scenario where permission is denied by logging an appropriate message.

coma

Conclusion

Integrating Firebase push notification Cloud Messaging into a React application enables efficient and effective handling of both foreground and background alerts. We’ve looked at how to configure the Firebase Cloud Messaging in React JS, manage token permissions, and handle notifications in various states in different browsers including Safari. Implementing these features improves user engagement through timely and appropriate alerts.

Nadeem K

Associate Software Engineer

Nadeem is a front-end developer with 1.5+ years of experience. He has experience in web technologies like React.js, Redux, and UI frameworks. His expertise in building interactive and responsive web applications, creating reusable components, and writing efficient, optimized, and DRY code. He enjoys learning about new technologies.

Keep Reading

Keep Reading

Mindbowser is excited to meet healthcare industry leaders and experts from across the globe. Join us from Feb 25th to 28th, 2024, at ViVE 2024 Los Angeles.

Learn More

Let's create something together!