How to Implement Push Notification with Node.js and Service Worker
Tags: javascript, beginners, node, tutorial
Published: 2022-09-21 14:32:22

Push notification has become an integral part of the web whether you are building a complex social media platform or you are building a simple blog, push notification just makes it easier to get messages across to users on the web easy.

We would be building a mini project to show how push notifications works on the server and client side


## Content
- [What are Push Notifications](#what-are-push-notifications)
- [How It Works](#how-it-works)
- [Prequisites](#prequisites)
- [Let's Begin](#lets-begin)
- [Generating Vapid Keys](#generating-vapid-keys)
- [Registering Push Notification](#registering-push-notification)
- [Subscribing To Push Notification](#subscribing-to-push-notification)
- [Sending Push Notification](#sending-push-notification)
- [Recieving and Displaying Push Notification](#recieving-and-displaying-push-notification)
- [Conclusion](#conclusion)


So...

## What are Push Notifications

Push Notifications are messages sent to a users device whether or not they are currently interacting with your website or application.

## How It Works

For push notification to work over the web we need something called **Service Workers**

Service Worker is a script that works on browser background without user interaction independently.If you need more info on that [Click Here](https://web.dev/learn/pwa/service-workers/)

## Prequisites

Basic Knowledge of

 - [Javascript](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
 - [Nodejs](https://nodejs.org/en/)
 - [Express.js](https://expressjs.com/)



## Let's Begin

We would be starting on the server side
Create a folder for your project let's call our folder `my-push-notifier` and

Open your terminal and navigate to the folder created then run these commands

`npm init -y`


`npm install express web-push`

Create an `app.js` file

![App.js Setup](https://res.cloudinary.com/d-cloud-storage/image/upload/v1663175056/Screenshot_2022-09-14_at_18.03.47_s6wo5z.png)

In the `package.json` file generated add this to the `script` object

`"start": "node app.js",`

Start your server with `npm run start` or `node app.js` your server should be running if everything was done correctly

## Generating Vapid Keys

Vapid keys are needed before we can send push notifications. Why ?

Well [two reasons](https://stackoverflow.com/questions/40392257/what-is-vapid-and-why-is-it-useful)

> The first is to restrict the validity of a subscription to a specific application server (so, by using VAPID, only your server will be able to send notifications to a subscriber).

> The second is to add more information to the push notification, so that the push service operator knows who is sending the notifications. If something is going wrong with your notifications, the operator knows who you are and can contact you. Moreover, they can offer you some kind of interface to monitor your push notifications.

Vapid keys can be generated online using


_[Vapid Keys Generator](https://www.stephane-quantin.com/en/tools/generators/vapid-keys)_

#### OR

In your terminal run this command to install [`web-push`](https://www.npmjs.com/package/web-push)

`npm install web-push`

Then generate your keys with this command

 `./node_modules/.bin/web-push generate-vapid-keys`

![Generated Vapid Keys](https://res.cloudinary.com/d-cloud-storage/image/upload/v1663173368/Screenshot_2022-09-14_at_17.34.17_coz3bt.png)

Copy the keys generated and save it somewhere.

In the `app.js ` file set up the webpush with your keys

![Set Up](https://res.cloudinary.com/d-cloud-storage/image/upload/v1663176097/Screenshot_2022-09-14_at_18.21.18_w4ljrg.png)

Replace `{YOUR_EMAIL}` with your any email you want to set up with

## Registering Push Notification

In our `app.js` file we would be creating an endpoint that allows users subscribe for push notification,
Create a `subscribers.json` file, in file add an empty array `[]`, The endpoint gets the subscriber's detail from the request body and saves it to a file
 

```js
app.post("/subscribe", async (req, res) => {
    try {
        // Subscription Details From the client side , We would get back to this
        const subscription = req.body;
        subscribers.push(subscription);

        // Save the new subscrber to the subscribers file
        fs.writeFileSync("./subscribers.json", JSON.stringify(subscribers));

        res.status(201).send("Subscription Saved");
    } catch (error) {
        console.error(error);
    }
});
```

## Subscribing To Push Notification

Now on the client side, create a `client` folder in our project folder and create the following files in the `client` folder

1. `index.html` with the following code

```html
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Push Notifications Using Node</title>
    </head>

    <body>
        <h1>Push Notifications Using Node</h1>
    </body>
    <script src="client.js"></script>
</html>
```
2. `client.js`
3. `worker.js`

Before we move forward add the following code to your `app.js` on the server side so html is rendered from the server

```js  
const path = require("path")
app.use(express.static(path.join(__dirname, 'client')))
```
Fist we would be creating a function in  `client.js` that subscribes for push notification on our server for we would be using the browser window [navigator](https://www.w3schools.com/js/js_window_navigator.asp) 

```js

const publicVapidKey = "{VAPID_PUBLIC_KEY}";



async function subscribeToPush() {
    console.log("Registering service worker...");
    const register = await navigator.serviceWorker.register("/worker.js", {
        scope: "/"
    });
    console.log("Service Worker Registered...");

    console.log("Registering Push...");
    const subscription = await register.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(publicVapidKey)
    });
    console.log("Push Registered...");

    console.log("Subscribing for Push ...");
    await fetch("http://localhost:1999/subscribe", {
        method: "POST",
        body: JSON.stringify(subscription),
        headers: {
            "Content-Type":"application/json"
        }
    });
}



function urlBase64ToUint8Array(base64String) {
    const padding = "=".repeat((4 - base64String.length % 4) % 4);
    const base64 = (base64String + padding)
        .replace(/\-/g, "+")
        .replace(/_/g, "/");

    const rawData = window.atob(base64);
    const outputArray = new Uint8Array(rawData.length);

    for (let i = 0; i < rawData.length; ++i) {
        outputArray[i] = rawData.charCodeAt(i);
    }
    return outputArray;
}
```

## Sending Push Notification

For the tutorial we would be sending notifications every minutes to our subscribers to do that we would create a function in our `app.js` on the server side

```js
// Sending push notification to subscribers
const subscribers = require("./subscribers.json")
const fs = require("fs")
async  function sendPushNotificaiton() {
    for (let i = 0; i < subscribers.length; i++) {
        const subscription = subscribers[i];
        //Notification Payload, this could contain more information about the notification
        const payload = {
            title: "Push Test", 
            body: " Push Notification Message",
            icon: "https://blog.mensaiah.com/assets/round_logo.png",
        };

        //Pass object into sendNotification
        await webpush.sendNotification(subscription, JSON.stringify(payload));
    }

}

//Send Notification Every Minute
const durationInMillisecond  = 60 * 1000
setInterval(sendPushNotificaiton,durationInMillisecond);

```



## Recieving and Displaying Push Notification

Remember our `worker.js`  file created on the client side. We would be listen for a push notification so it can be displayed

```js

self.addEventListener("push", e => {

    // Data from service
    const data = e.data.json();
    console.log("Push Recieved...");
    self.registration.showNotification(data.title, {
        body: data.body,
        icon: data.icon,
    });
});

```
You can find more information on displaying push notification [here](https://web.dev/push-notifications-display-a-notification/);


## Run Application
In our `client.js ` call the `subscribeToPush` function we created above, NB: Not all browsers support service workers so we would be doing this

```js
// Only subscribe to push notification when browser supports service worker
if ('serviceWorker' in navigator) {
    subscribeToPush().catch(console.log);
}

```
On your browser (I recommend using chrome), visit `http://localhost:1999/`  to start recieving notification form the server.
Click on allow when  a prompt ask if you want to show notifications

 ## Conclusion

 This tutorial does not exhaust all possibilities of service workers, so I suggest reading  and trying out more on the topic. Below are articles I recommend


 - [Web Push and Notifications](https://web.dev/notifications/)
 - [Service Workers](https://web.dev/learn/pwa/service-workers/)
 - [More on Service Workers](https://developer.chrome.com/docs/workbox/service-worker-overview/)
 - [What Are Service Workers and How to Use Them?](https://rajat-m.medium.com/what-are-service-workers-and-how-to-use-them-e993c1f497e6)