DEV Community

Cover image for Getting Started with Web Push Notifications
Alex Rudenko
Alex Rudenko

Posted on • Originally published at 60devs.com

Getting Started with Web Push Notifications

I have heard about Web push notifications and Service Workers many times, but I have never implemented them until the last week for Just Comments. So I decided to share my notes about this technology.

First of all, there are plenty of articles and useful documentation about Web push notifications so I won't add something new to it. I will try to summarize what I feel one needs to understand and know to get started quickly and implement a basic version of Web Push notifications.

Let's start with some key facts:

#1 Push notifications rely on multiple separate browser APIs

The entire feature of Push Notifications involves Push API and Notifications API which can be used separately. Also, it relies on Service Workers because only they can run in the background to be able to receive push notifications even if the user closed the sending website.

#2 Not all browsers support Push Notifications (yet)

Currently, IE && Opera Mini doesn't support Service Workers and Push API and, additionally, iOS Safari, Chrome for Android, Samsung Browser and UC browser for Android don't support Web Notifications API.

It means that you need to detect if the browser supports required APIs or not when you implement push notifications.

Big Diagram of How This Works

I created a simple diagram to wrap my head around different APIs and concepts. It connects various pieces via a sequence of actions/relationships between them.

So all starts with some JavaScript code on your Web page which registers (1) a service worker. The service worker provides (2) a service worker registration object which, in turn, gives access (3) to an instance of Push Manager. The push manager can provide (4) us a Push Subscription if the user allows. This subscription object can be sent to your backend (5). On the server, you can use the subscription to send a message (6) to the user's browser. The service worker receives (7) the message, but it is not automatically shown to the user. The service worker parses the message and can decide what to do with it. Normally, the worker displays a Notification (8) using the Notification API.

The Coding Part

As I mentioned in the key facts, not all browsers support the APIs, so we need to check if the user’s browsers support service workers:

function supportsPushNotifications() {
  return 'serviceWorker' in navigator && 'PushManager' in window;
}

supportsPushNotifications() === true // if the browser supports needed APIs
Enter fullscreen mode Exit fullscreen mode

After we check that we can use Service Workers, we can start with the first step and register a service worker:

navigator
  .serviceWorker
  .register('/sw.js')
  .then(swRegistration => {
    // TODO step 2 & 3 here
  })
  .catch(err => {
    console.log('serviceWorker.register failed', err);
  });
Enter fullscreen mode Exit fullscreen mode

This code fetches sw.js at the root of your website. The register function returns a promise. Therefore, we handle it with .then for a successful case and .catch if something goes wrong.

Now, we can implement the step 2 & 3 which requires the swRegistration:

const applicationServerKey = '';
swRegistration
  .pushManager
  .getSubscription()
  .then(subscription => {
    const isSubscribed = !(subscription === null);
    if (!isSubscribed) {
      return swRegistration.pushManager
        .subscribe({
          userVisibleOnly: true,
          applicationServerKey,
        })
        .then(sendSubscriptionToServer);
    }
    sendSubscriptionToServer(subscription);
  })
  .catch(err => {
    console.log('getSubscription failed', err);
  });
Enter fullscreen mode Exit fullscreen mode

Don't worry about applicationServerKey for now. applicationServerKey allows associating the subscription with your server. I will explain how to obtain this key later.

So what happens here: we call the pushManager.getSubscription method which returns a subscription if the user has already allowed push notifications and null otherwise. If we already have a subscription, we can send it to the backend. If not, we call pushManager.subscribe to ask the user to allow push notifications.

Now, for the step 5, you can use any method you like to send the subscription object to your server. I recommend stringifying it first with JSON.stringify(subscription).

For sending a message from your server to the client, I recommend using the web-push module:

const webpush = require('web-push');

const vapidKeys = {
  publicKey: '',
  privateKey: '',
};

webpush.setVapidDetails(
  'mailto:your@email',
  vapidKeys.publicKey,
  vapidKeys.privateKey
);

webpush.sendNotification(
  JSON.parse(subscription),
  JSON.stringify({
    title: 'Title',
    icon: 'https://your-site.com/assets/push-icon.png',
    body: 'Body',
    url: 'https://your-site.com/url-to-open',
  })
)
Enter fullscreen mode Exit fullscreen mode

And now in steps 7 & 8, we circle back to sw.js, the service worker code responsible for receiving and displaying a push message:

self.addEventListener('push', function(event) {
  const message = JSON.parse(event.data.text());
  const title = message.title;
  const url = message.url;
  const options = {
    body: message.body,
    icon: message.icon,
    badge: message.badge,
    data: url,
  };
  event.waitUntil(self.registration.showNotification(title, options));
});

self.addEventListener('notificationclick', function(event) {
  event.notification.close();
  event.waitUntil(clients.openWindow(event.notification.data));
});

Enter fullscreen mode Exit fullscreen mode

Here, two event listeners are defined. With the push listener, we parse the message and invoke the showNotification method to display a notification. On notificationclick we close the notification and navigate to the URL sent via the push message.

Generating Keys

You can use the web-push library to generate keys. The key generation needs to be done once. Both the frontend and the backend use the same public key, and the backend only uses the private key:

const webpush = require('web-push');
const vapidKeys = webpush.generateVAPIDKeys();
console.log(vapidKeys);
Enter fullscreen mode Exit fullscreen mode

You should specify the keys in the previous code snippets, where needed.

Conclusion

I find the APIs for Push Notifications to be quite simple and straightforward. Nevertheless, it takes quite some time, in the beginning, to wrap your head around all concepts and moving parts.

I hope you find these notes useful and you'll come back to them once you need to implement push notifications. And if this time comes, please don't ask for permissions as soon as the web page loads: it's annoying, and most people would block it.

Thanks for reading!

Latest comments (2)

Collapse
 
miqueasgutierrez profile image
miqueasgutierrez

Excellent explanation, you can also integrate INDIGITALL, it is a good service, it allows you to send Notifications with an animated image, Segmented, Geolocated and many more functions, it is great.
Here you can see the installation for your platform: docs.indigitall.com/

Collapse
 
maxmax profile image
Max trueno

Great option to avoid coding and send push notifications!