Web Push Notifications 🔔

·

4 min read

Web Push Notifications 🔔

Overview

Web push notification consists of two parts:

  1. Push API
  2. Notification API

Push API enables the developers to take the message to the users even if they are not on their site.

Notification API helps to present small chunks of information to a user.

How it works?

Client side

web-push-subscription.png

1.) Register a service worker to your app. You'll get a promise that resolves to aServiceWorkerRegistration object.

const registration = await navigator.serviceWorker.register('./service-worker.js', {scope:'/'});

2.) Using the ServiceWorkerRegistration object that we got earlier, use the subscribe method of the PushManager to create a PushSubscription object.

PushSubscription object contains the unique details that are sufficient to identify the user to send the push messages. The endpoint is unique to each client. A PushSubscription object looks like this:

{ "endpoint": "fcm.googleapis.com/fcm/send/c1KrmpTuRm…", "expirationTime": null, "keys": { "p256dh": "BGyyVt9FFV…", "auth": "R9sidzkcdf…" } }

const subscribeOptions = {
  userVisibleOnly: true,
  applicationServerKey: urlBase64ToUint8Array(VAPID_PUBLIC_KEY) //we'll cover this later in the article
 };
const pushSubscription = await registration.pushManager.subscribe(subscribeOptions);

But what is VAPID_PUBLIC_KEY?? Let's see later in this article.

3.) Now, for the app to send push messages to the user, it has to get hold of the subscription endpoint. But, how will the app get it? Correct, we'll make a POST call to the server and store it in the database.

await postToServer('/add-subscription', pushSubscription);

This is all you have to do on the client side.


Server side

server-push-message.png

1.) When the app decides to notify the user(s), the server gets the PushSubscription object of that/those user(s) from the DB it is stored.

2.) And the server makes a web push protocol request to the push service. web-push library helps us to do this.

const vapidDetails = {
    subject: process.env.VAPID_SUBJECT,
    publicKey: process.env.VAPID_PUBLIC_KEY,
    privateKey: process.env.VAPID_PRIVATE_KEY,
};
const options = {
   vapidDetails: vapidDetails
};
await webpush.sendNotification(subscription, notification, options)

3.) The push service receives your request, authenticates it, and routes the push message to the appropriate client.

4.) When a client browser receives a pushed message, it decrypts the push message data and dispatches a push event to your service worker.

5.) In your service worker, push event is triggered. In the push event handler, you call ServiceWorkerRegistration.showNotification() to display the information as a notification.

self.addEventListener('push', (event) => {
    let notification = event.data.json();
    const options = { 
        ...notification.options,
        icon: 'icon.png',
        image: 'image.png',
        badge: 'badge.png'
        //there are a lot more options available
    }
    self.registration.showNotification(
        notification.title,
        options
    );
});

Yay🎉🎉, it's all done. Users will now see notifications like below in their browser.

Screenshot 2022-01-09 at 11.27.55 PM.png

Wait, do you remember the VAPID thing I mentioned earlier? Let's see what it is.


VAPID

The application server keys, also known as VAPID keys, are unique to your server. They allow a push service to know which application server subscribed a user and ensure that it's the same server triggering the push messages to that user.

It makes sure that no other server is trying to send notifications to the client.

How it works?

Using the web-push library, we can generate VAPID keys like

npx web-push generate-vapid-keys

You'll get a private key and a public key.

When subscribing to the pushManager (client side - point 2), we have to use the Public key.

When the server makes a web push protocol request to the push service (server side - point 2), it uses both public and private keys.

The push service takes care of the authentication. It allows the server to communicate the message to the client only if the keys match.


Is this all the code we need to enable push notifications in our app? Definitely not! 😛 Obviously, we need to handle feature detection, error scenarios, etc as well.

Somethings like,

const isNotificationAPISupported = () => 'Notification' in window;
const isNotificationPermissionAllowed = () => Notification.permission === 'granted';
const askNotificationPermission = () => Notification.requestPermission();

const isServiceWorkerAvailable = () => 'serviceWorker' in navigator;
const isPushSupported = () => 'PushManager' in window;

I've tried to cover the topic as simple as possible. This is just to give an overview of what Web Push Notification is and how it works.

MDN docs:

Push API

Notification API

Demo

You can see a live demo here: Browser push notifications

Code

You can find the source code here: web-push-notification

Â