Getting Started with Web Push Notifications
Tags: web, node, javascript, webdev
Published: 2018-04-09 19:14:43

---
title: Getting Started with Web Push Notifications
published: true
description: Getting started with Push Notifications for Websites
tags: web,node,javascript,webdev
canonical_url: https://60devs.com/getting-started-with-web-push-notifications.html
cover_image: https://60devs.com/img/article-push/preview.png
---

I have heard about Web push notifications and Service Workers many times, but I have never implemented them until the last week for <a href="https://just-comments.com">Just Comments</a>. 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](https://caniuse.com/#feat=serviceworkers) and [Push API](https://caniuse.com/#feat=push-api) and, additionally, iOS Safari, Chrome for Android, Samsung Browser and UC browser for Android don't support [Web Notifications API](https://caniuse.com/#feat=notifications).

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.

<div style="text-align: center;"><img title="Web Push API Workflow" src="https://60devs.com/img/article-getting-started-with-web-push-api/push.png" /></div>

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:

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

supportsPushNotifications() === true // if the browser supports needed APIs
```

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

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

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`:

```js
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);
  });
```

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:

```js
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',
  })
)
```

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

```js
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));
});

```

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:

```js
const webpush = require('web-push');
const vapidKeys = webpush.generateVAPIDKeys();
console.log(vapidKeys);
```

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!