DEV Community

shahriarKabir44
shahriarKabir44

Posted on

Send Push Notifications Using Vanila JS! (Example with ExpressJS)

Introduction:

Making a lucrative UI or smooth UX are no longer enough to keep your clients attracted to you now-a-days! You need more. You need User Engagement. Specially if you're selling something online, an e-commerce perhaps. And you want to inform your users about a big sale that's coming on a specific festival. How? You might think that if you had an app, you might send your users some push notifications. Which is true but not really feasible in many cases specially when you're new to business. and then you wonder..

 What if a web application could send push notificatons? πŸ€”
Enter fullscreen mode Exit fullscreen mode

Well lucky you because you're at the right spot!

In this article we'll...

  1. Do some basics.
  2. Create a simple web app with frontend and backend.
  3. Dive a bit deep on how it works.
  4. Some FAQs πŸ€“

So, let's go!

Environment Setup.

Fire up your vscode in a folder and create a js file. This will be the server part from where we'll send the notifications. Now create a new project using npm with the command

npm init -y
Enter fullscreen mode Exit fullscreen mode

This will create a package.json file for you.
we need to install 2 npm packages.

  1. dotenv To store private and public VAPID key. (More on these later)
  2. web-push To actually send the notifications.

Install them with the npm install command.

The plan (Bird's Eye View):

There are two major players in this game.
ServiceWorkers and Web-Push
At first, we need to create to two keys which are called VAPID (Voluntary Application Server Identification) keys one is public and another is private (Asymmetric encryption/decryption but let's not dig deeper here).
The idea is that we register a serviceworker and use the subscription object to create a PushSubscription object using the public VAPID key.
We then send this object to the backend with a POST request. The server stores it. And in any event, the server uses the client's subscription object to send the notification.
In short...

Data Flow

Enough with the chit chat!

Let's Move!

Project Structure:

root/
β”œβ”€β”€ client/
β”‚   β”œβ”€β”€ index.html
β”‚   β”œβ”€β”€ index.js
β”‚   └── worker.js 
β”œβ”€β”€ app.js
β”œβ”€β”€ .env
β”œβ”€β”€ package.json
└── README.md
Enter fullscreen mode Exit fullscreen mode

The Frontend:

HTML

We'll keep it as simple as possible. We're only interested on getting a push notification on a button click. No fancy design, no CSS. Just a single button in HTML.

ServiceWorker

We'll limit our serviceworker's role to just receiving push notifications and show it.
A notification needs to have three properties:

  • Icon
  • Title
  • Body So, we'll design our payload object keeping this in mind. We'll use a fixed notification icon in this demonstration.

Nicely done!

The backend

Let's do the bare minimum in our backend part in our app.js file.
Such as:

  1. Including the necessary packages.
  2. Configuring the port.
  3. Pointing the static files directory.
  4. Configuring the environment variable. (We'll store our keys in the .env file btw)
  5. And an API endpoint to receive and store the client's info.

Great! now the crucial part!

Generating the VAPID keys

Run the following command on your terminal

npx web-push generate-vapid-keys
Enter fullscreen mode Exit fullscreen mode

You'll get an output like this..

=======================================

Public Key:
<Public Key>

Private Key:
<Private Key>

=======================================
Enter fullscreen mode Exit fullscreen mode

Copy the keys and store them in your .env file.
Now, we register the ServiceWorker.
Here's what we'd do:

  1. Register the ServiceWorker (worker.js in our case)
  2. Create Push Subscription. 2.1. Convert the public VAPID key to Uint8 Array. 2.2. Create the PushSubscription object
  3. Post it to the backend.

Like so..

I'm sure that you're wondering what's happening in the following code:

 function convertToUnit8Array(base64str) {
    const padding = '='.repeat((4 - (base64str.length % 4)) % 4)
    const base64 = (base64str + padding).replace(/\-/g, '+').replace(/_/g, '/')
    const rawData = atob(base64)
    var outputArray = new Uint8Array(rawData.length)
    for (let n = 0; n < rawData.length; n++) {
        outputArray[n] = rawData.charCodeAt(n)
    }
    return outputArray
}

What it does is basically

  1. Pad the string with '=' character to make its length divisible by 4.
  2. Convert Base64URL β†’ normal Base64
  3. Decode Base64 β†’ raw binary string Basically, converting the human readable public key to machine readable byte array.

Now let's update our server code, shall we?

We'll configureour webpush with our public and private VAPID keys and an email address. For now, we're not providing any valid email.
We'll also implement a get API called /sendNofication to send a notification to the client.
Here's the updated code:


Great! We're now ready!
Fire up your server with the following command:
node app.js
Enter fullscreen mode Exit fullscreen mode

And open your browser on the following URL:

Send Push Notifications Using Vanila JS! (Example with ExpressJS)

Making a lucrative UI or smooth UX are no longer enough to keep your clients attracted to you now-a-days! You need more. You need User Engagement. Specially if you're selling something online, an e-commerce perhaps. And you want to inform your users about a big sale that's coming on a specific festival. How? You might think that if you had an app, you might send your users some push notifications. Which is true but not really feasible in many cases specially when you're new to business. and then you wonder..

 What if a web application could send push notificatons? πŸ€”
Enter fullscreen mode Exit fullscreen mode

Well lucky you because you're at the right spot!

In this article we'll...

  1. Do some basics.
  2. Create a simple web app with frontend and backend.
  3. Dive a bit deep on how it works.
  4. Some FAQs πŸ€“

So, let's go!

Environment Setup.

Fire up your vscode in a folder and create a js file. This will be the server part from where we'll send the notifications. Now create a new project using npm with the command

npm init -y
Enter fullscreen mode Exit fullscreen mode

This will create a package.json file for you.
we need to install 2 npm packages.

  1. dotenv To store private and public VAPID key. (More on these later)
  2. web-push To actually send the notifications.

Install them with the npm install command.

The plan (Bird's Eye View):

There are two major players in this game.
ServiceWorkers and Web-Push
At first, we need to create to two keys which are called VAPID (Voluntary Application Server Identification) keys one is public and another is private (Asymmetric encryption/decryption but let's not dig deeper here).
The idea is that we register a serviceworker and use the subscription object to create a PushSubscription object using the public VAPID key.
We then send this object to the backend with a POST request. The server stores it. And in any event, the server uses the client's subscription object to send the notification.
In short...

Data Flow

Enough with the chit chat!

Let's Move!

Project Structure:

root/
β”œβ”€β”€ client/
β”‚   β”œβ”€β”€ index.html
β”‚   β”œβ”€β”€ index.js
β”‚   └── worker.js 
β”œβ”€β”€ app.js
β”œβ”€β”€ .env
β”œβ”€β”€ package.json
└── README.md
Enter fullscreen mode Exit fullscreen mode

The Frontend:

HTML

We'll keep it as simple as possible. We're only interested on getting a push notification on a button click. No fancy design, no CSS. Just a single button in HTML.

ServiceWorker

We'll limit our serviceworker's role to just receiving push notifications and show it.
A notification needs to have three properties:

  • Icon
  • Title
  • Body So, we'll design our payload object keeping this in mind. We'll use a fixed notification icon in this demonstration.

Nicely done!

The backend

Let's do the bare minimum in our backend part in our app.js file.
Such as:

  1. Including the necessary packages.
  2. Configuring the port.
  3. Pointing the static files directory.
  4. Configuring the environment variable. (We'll store our keys in the .env file btw)
  5. And an API endpoint to receive and store the client's info.

Great! now the crucial part!

Generating the VAPID keys

Run the following command on your terminal

npx web-push generate-vapid-keys
Enter fullscreen mode Exit fullscreen mode

You'll get an output like this..

=======================================

Public Key:
<Public Key>

Private Key:
<Private Key>

=======================================
Enter fullscreen mode Exit fullscreen mode

Copy the keys and store them in your .env file.
Now, we register the ServiceWorker.
Here's what we'd do:

  1. Register the ServiceWorker (worker.js in our case)
  2. Create Push Subscription. 2.1. Convert the public VAPID key to Uint8 Array. 2.2. Create the PushSubscription object
  3. Post it to the backend.

Like so..

I'm sure that you're wondering what's happening in the following code:

 function convertToUnit8Array(base64str) {
    const padding = '='.repeat((4 - (base64str.length % 4)) % 4)
    const base64 = (base64str + padding).replace(/\-/g, '+').replace(/_/g, '/')
    const rawData = atob(base64)
    var outputArray = new Uint8Array(rawData.length)
    for (let n = 0; n < rawData.length; n++) {
        outputArray[n] = rawData.charCodeAt(n)
    }
    return outputArray
}

What it does is basically

  1. Pad the string with '=' character to make its length divisible by 4.
  2. Convert Base64URL β†’ normal Base64
  3. Decode Base64 β†’ raw binary string Basically, converting the human readable public key to machine readable byte array.

Now let's update our server code, shall we?

We'll configureour webpush with our public and private VAPID keys and an email address. For now, we're not providing any valid email.
We'll also implement a get API called /sendNofication to send a notification to the client.
Here's the updated code:


Great! We're now ready!
Fire up your server with the following command:
node app.js
Enter fullscreen mode Exit fullscreen mode

And open your browser on the following URL:
localhost:4000

And follow me!

Demo

BOOM! We've implemented push notifications!
enter image description here

FAQs:

  1. Is it scalable? HELL YEAH πŸ’ͺ It's the push notification services that does the main heavy lifting. Not you! (E.g. Google, Firefox, Apple etc depending on the browser). If you inspect the PushSubscription object, you'll find a property called endpoint. When your server wants to send you a push notification, it basically becomes a REST API client and calls API mentioned in the endpoint property.
    1. Do you have to manage any states? You might think that since it's real-time, you'll have to store some state in the server like WebSocket. Luckily that's not the case. You only need to store the user's subscription data in the database.

Conclusion:

So, we've implemented push notifications using vanilla js! Please let me know how I can improve this article.
Here's the entire codebase btw if you're interested:
Git Repository

Top comments (0)