Push notifications allow users to get updates and engage with your content. You can send push notifications via browsers (Desktop/Mobile) which support Push & Notification API.
Below browsers support Push & Notification API:
- Chrome Desktop and Mobile (version 50+)
- Firefox Desktop and Mobile (version 44+)
- Opera on Mobile (version 37+)
Let’s see what’s involved in setting up a push notification service for a site.
It’s inside the service worker’s ‘push’ event that you can perform any background tasks. You can make analytics calls,cache pages offline and show notifications.
You must check if the browser supports service workers.
The PushManager interface of the Push API provides a way to receive notifications from third-party servers as well as request URLs for push notifications.
You must check if the browser supports push manager.
Service Worker Registration
The browser will then run the file in a service worker environment.
Once we register the service worker we need to get permission from the user to send push notifications.
If the user blocks the permission request then they have to manually unblock the site in the browser settings panel.
After registering the service worker and getting user permission, we need to subscribe the user.
We need to generate VAPID keys and submit to the push service. These keys are used by the push service to identify the application subscribing the user and ensure that the same application is the one messaging the user.
Once you subscribe you will receive an endpoint, associated with the app’s public key and an identifier (push subscription).
Later, when you want to send a push message, you’ll need to create an Authorization header which will contain information signed with your application server’s private key and submit to that endpoint.
We need to store the push subscription details by sending it to our server so that we can use it to send messages to a user.
To send a push message we need to do a web push by sending a payload with an Authorization header signed with the private key.
The push service will use the public key to decrypt the authorization header and verify that it is the same application that subscribed the user which is trying to send a message.
It will then send the push message to the user’s device when the browser becomes active.
Firebase Cloud Messaging
Firebase Cloud Messaging (FCM) is a cross-platform messaging solution that lets you reliably deliver messages at no cost.
We’ll see how we can use FCM to send notification messages to the client.
Below is how our application will work. We won’t go into the details of how to build and deploy a react app as it is outside the scope of this guide.
Source code of the application can be found here -
Sample notification page:
Push API relies on a few different pieces of technology, including Web App Manifests and Service Workers.
Let’s see the steps involved in enabling Push API for your react app. We’ll use
Firebase SDK to facilitate instant messaging.
Add Firebase to your app
To add Firebase to your app, you’ll need a Firebase project.
- Create a firebase project in the Firebase console.
- Get your app config which we will use to initialize firebase in your react app.
- Install firebase npm module.
firebase.js file where we will initialize our app with the configuration details we got from our firebase project and also export the
We will use the
messaging reference later to register our service worker and handle incoming push notifications.
Next, we will create a
notifications.js react component page which will check if the browser supports
Service Worker and
Push API. Based on it we will either display a message mentioning that push notifications are not supported or our subscription options.
Here, we have used
material-ui for styling the page. Also, we import our
firebase.js file which we had created previously.
We are following the passive approach here, which is to have a button or toggle switch that enables / disables push messages in a location on the page that is consistent throughout a site. Good UX design is to offer a way out for the user from the push messages and also not to ask for push permissions as soon as the user visits the page.
Next, we need to create a service worker file and register it.
Create a new file
firebase-messaging-sw.js inside the
pwa directory with below contents.
We then register the service worker file by updating
We mentioned the path of the worker file as
/firebase-messaging-sw.jsbut we had placed the file inside
pwadirectory. This is because, later, we will be updating webpack config to copy the files to the
publicfolder from where the static assets will be served. Based on your app design and bundler used you might have to update the path accordingly.
We have set
none, so that the HTTP cache will not be consulted when making requests for either the top-level /service-worker.js or for any imported scripted. Prior to Chrome 68, the update request for /service-worker.js would be made via the HTTP cache. Starting in 68, the HTTP cache will be ignored when requesting updates to the service worker script, so existing web applications may see an increase in the frequency of requests for their service worker script. Requests for importScripts will still go via the HTTP cache.
Every time our page loads, the browser will download the latest copy of service worker and will do a byte-to-byte comparison to see if anything has changed. If so, it will activate the new copy otherwise it won’t perform the update.
Also, if it notices any difference with the latest copy it won’t immediately activate the new service worker. The browser will wait until the current service worker controlls zero clients. You can however, force an update to be done.
Notification messages are handled differently depending on whether the page is in the foreground (has focus), or in the background, hidden behind other tabs, or completely closed.
Background Message Handling
We had earlier defined
firebase-messaging-sw.js file which imported the firebase scripts and initialised the messaging component. That will take care of background message handling.
Whenever, a push event is sent, the service worker will get activated. The JS script is then run and the messaging component will make use of the Notification API to display the message in a standard format.
We will look at how the message is constructed with the content and action links in our server side section.
Foreground Message Handling
When your page in focus, then you need to explicity handle how your message gets displayed. For example, we need to make use of the
onMessage function to handle the incoming message and show the notification using the service worker.
firebase.js file with the
Here, we get the message, icon, link and use the service worker to display the notification. We also create a notification action to handle click events.
firebase-messaging-sw.js with the
Whenever, the notification is clicked, it will open the link in a new window and will close the notification.
So far, we have seen how to register service workers, display notifications etc. Inorder to display push notifications the user has to accept it. If incase, the user rejects or blocks the site we won’t be able to send any notifications until the user manually revokes it.
notifications.js file with logic to handle user permissions.
We do couple of things here:
- Check if the user has already granted the permission to send push notifications. If not, we request for it.
- Also we check if the token is available in the local storage (we will store it later).
- Finally, if above conditions aren’t satisfied we request for a token. If you request for it multiple times you will only get the same instance token back. We then send this token to our server to have it stored in firestore (or any file/database) as we need it to send push notifications. Also, we store the token in localStorage to quickly identify if the user has subscribed for notifications or not and display appropriate toggle switches.
- If incase, the user has refused the permission then we can display the required messages to the user perhaps as a toast/snackbar.
- Registration token may change when:
- The app deletes Instance ID
- The app is restored on a new device
- The user uninstalls/reinstall the app
- The user clears app/site data
You need to call ‘onTokenRefresh’ to send the refreshed token to your server.
We need to provide subscription options to our user based on whether he has already subscribed / not.
For example, in our
notifications.js we could do something like below:
Initially, we set the subscription toggle switch state to
false. In our previous function,
notificationPermission we had set the token in localStorage.
When the component mounts, we check if that token is available, if so we enable the toggle switch to indicate to the user that he has already subscribed.
If incase, this is a new subscription, we first get the permissions from the user and generate the registration token. In our
notificationPermission function, we store the registration token in our database and also in localStorage.
We are also subscribing the user to a topic in function call
You can either send notifications to a set of users using their registration tokens (or) subscribe them to a topic and just publish a message to the topic. If incase, of publish-subscribe model, the message will get sent to all subscribers of topic.
We will look into them more in detail later.
pwa directory in
src folder which will contain the
This indicates that FCM is authorized to send messages to this app.
Link the manifest in your index file.
If you are using webpack to generate your build files then you can use
copy-webpack-plugin to copy the manifest file to the build directory.
If you are using Nginx to serve your static assets then you can specify to gzip the manifest file and specify content expiry time.
We now have everything wired up on our client side. So, how can we test everything works fine on our client side before proceeding to the server side of things.
Run your react app in your local. In your subscription page, provide the user permissions and get the registration token from localStorage or your database.
Once you have the registration token we can then publish a message to test if the notification gets displayed when the app is in focus or in background.
Check Registration Token Status
Send a curl request to Google IID API with the registration token in the url and
apiKey (from your firebase project configuration) in the Authorization header.
You will get back details like below:
Sample Notification Message
We then send a message to test if the notification gets shown to the user. We had previously used the project
But, for sending the message we will use the FCM v1 HTTP protocol instead of the legacy protocol which will require JWT access token to be passed along the request.
To generate the access token you can make use of fcm-http-oauth. Follow the steps in the README to generate a service account in your firebase project.
Let’s now send the message to a particular user by providing firebase project id, jwt and the registration token:
We had looked so far on how to subscribe a user to receive push notifications. We will now look at storing the registration tokens in firestore and sending notification messages using firebase SDK.
Cloud Firestore is a flexible, scalable database for mobile, web, and server development from Firebase and Google Cloud Platform.
It keeps your data in sync across client apps through realtime listeners and offers offline support for mobile and web so you can build responsive apps that work regardless of network latency or Internet connectivity.
Creating New Database
Create a new firestore database in test mode inside your firebase project.
Rules tab add below rule to allow reads/writes only from your account:
Storing Registration Token
You can create a node js project which will be sending notifications to your users/use cloud functions/any other framework. In this guide, we will see how we can store tokens in firestore using node.js.
Generate a service account by following these steps:
In your firebase project, under project settings, choose
Generate new private keyto download your service account file.
We will use the service account to access firestore.
firebase-admin SDK to your node.js project.
We will define
firebase.js file which will perform the required operations.
This script exports two functions -
 storeAppInstanceToken - You will pass in the token which needs to be stored in a firestore collection. Also, adds a server timestamp to the document.
 deleteAppInstanceToken - Gets the docs which match the token and deletes them.
Sending User Notifications
We update the script
firebase.js to export below functions to be able to send push notifications -
We can use
buildPlatformMessage to generate a message and then pass it on to
sendFcmMessage to notify the user.
You can also subscribe/unsubscribe users to topics by calling
We had used firebase SDK for sending FCM messages. You can also make use of webpush or send the messages to the FCM HTTP App server endpoint.
So far, we had defined subscription, firebase and fcm actions.
We will use Express to expose them as API’s in a web server so that our client app can access them.
Install express as a dependency.
Create a new file named
index.js and define below API’s.
You can run the server with below command and access the endpoints via localhost e.g. send a POST request to http://localhost:1338/subscribe with appropriate JSON body content.
There are various cloud platforms available where you can deploy the node express server.