Push Notifications With NodeJS (Step-By-Step Example)

Welcome to a tutorial and example of how to send push notifications with NodeJS. It is no secret by now that browsers are capable of handling push notifications. But just how is it done? It is by all means not a walk in the park, but here’s a quick overview.

There are 3 main components when it comes to working with push notifications.

  • Client-side – The web page itself. Get the user’s consent to send push notifications and register a service worker.
  • Service Worker – Listen to push requests, and show the notifications.
  • Server-side – Send out push notifications.

That covers the quick basics, read on for the step-by-step example!

ⓘ I have included a zip file with all the source code at the start of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.

 

 

TABLE OF CONTENTS

Download & Notes Push Notification Useful Bits & Links
The End

 

DOWNLOAD & NOTES

Firstly, here is the download link to the example code as promised.

 

QUICK NOTES

  • A web server is not required, just NodeJS.
  • Push notifications will not work on Grade B and older browsers (see compatibility checks below).
If you spot a bug, feel free to comment below. I try to answer short questions too, but it is one person versus the entire world… If you need answers urgently, please check out my list of websites to get help with programming.

 

EXAMPLE CODE DOWNLOAD

Click here to download all the example source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

 

PUSH NOTIFICATIONS

All right, let us now get into the steps of building a simple push notification app using NodeJS.

 

STEP 1) DOWNLOAD REQUIRED NODE MODULES

  • Create your own project folder, for example, D:\push.
  • Open the command line, navigate to your project folder and run npm i express body-parser web-push.

Done. NPM will automatically fetch the modules into the node_modules folder.

 

STEP 2) GENERATE VAPID KEYS

2-vapid-keys.js
const vapidKeys = require("web-push").generateVAPIDKeys();
console.log(vapidKeys);

Next, run this to generate your own pair of public/private keys – node 2-vapid-keys.js. Keep the keys somewhere first, we will use them later… This script only needs to run once, but you can regenerate your keys at any time.

P.S. VAPID stands for Voluntary Application Server Identification. In simple terms, security and authentication to prevent your push notifications from getting hijacked.

P.P.S. We only use the private key on the server side. Do not expose it publicly.

 

 

STEP 3) CLIENT PAGE

GET PERMISSION TO SHOW NOTIFICATIONS

3-perm-sw.html
// (A) OBTAIN USER PERMISSION
// (A1) ASK FOR PERMISSION
if (Notification.permission === "default") {
  Notification.requestPermission().then((perm) => {
    if (Notification.permission === "granted") {
      regWorker().catch((err) => { console.error(err); } );
    }
    else { alert("Please allow notifications."); }
  });
}
 
// (A2) GRANTED
else if (Notification.permission === "granted") {
  regWorker().catch((err) => { console.error(err); } );
}

// (A3) DENIED
else { alert("Please allow notifications."); }

The first thing we do is to get the user’s permission to show notifications. This is actually pretty straightforward:

  • Notification.permission contains the status to show notifications.
    • default The user has neither granted nor denied permission.
    • granted The user has allowed notifications to show.
    • denied User disallowed notifications to show.
  • So what we are doing in this section:
    • If the user has not chosen to allow/deny, we show the prompt with Notification.requestPermission().
    • When the permission is granted, we proceed to register the service worker regWorker().
    • Lastly, prompt the user to allow notifications if denied. This is actually a bad annoying example, leave the users alone and respect their decision in your own project…

 

 

REGISTER SERVICE WORKER

3-perm-sw.html
 // (B) REGISTER SERVICE WORKER
async function regWorker () {
  // (B1) YOUR PUBLIC KEY - CHANGE TO YOUR OWN!
  const publicKey = "YOUR-PUBLIC-KEY";
 
  // (B2) REGISTER SERVICE WORKER
  const reg = await navigator.serviceWorker.register("4-sw.js", { scope: "/" });
 
  // (B3) SUBSCRIBE TO PUSH SERVER
  const sub = await reg.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: publicKey
  });
 
  // (B4) TEST PUSH
  await fetch("/mypush", {
    method: "POST",
    body: JSON.stringify(sub),
    headers: { "content-type": "application/json" }
  });
}
  • (B1) Remember the VAPID keys? Insert your public key here.
  • (B2) Register a service worker to listen to push calls, handle the notifications. For the uninitiated, service workers run in the background, even after the page is closed; Push notifications will show even after the page is closed.
  • (B3) Subscribe to the push server. Take note, a subscription object const sub is being returned here.
  • (B4) /mypush is an endpoint that we will build on the server to send out a dummy push notification. Here, we are just doing the lazy thing of “instantly send a test notification when all client setup is complete”. Take note that the subscription object const sub is being JSON encoded and passed to the server.

 

 

STEP 4) LISTEN TO PUSH WITH THE SERVICE WORKER

4-sw.js
// (A) INSTANT WORKER ACTIVATION
self.addEventListener("install", (evt) => {
  self.skipWaiting();
});
 
// (B) LISTEN TO PUSH
self.addEventListener("push", (evt) => {
  const data = evt.data.json();
  console.log("Push", data);
  self.registration.showNotification(data.title, {
    body: data.body,
    icon: data.icon,
    image: data.image
  });
});
  1. A small irritating part with service workers is the state – “installing, installed, activating, activated”. To prevent this example from failing, we will instantly activate the worker and skip waiting.
  2. Well, Captain Obvious to the rescue – Parse received JSON data from the server, show it in a notification with registration.showNotification().

 

STEP 5) PUSH SERVER

5-server.js
// (A) SETTINGS - CHANGE TO YOUR OWN!
const port = 80,
      mail = "your@email.com",
      publicKey = "YOUR-PUBLIC-KEY",
      privateKey = "YOUR-PRIVATE-KEY";
 
// (B) LOAD MODULES
const express = require("express"),
      bodyParser = require("body-parser"),
      path = require("path"),
      webpush = require("web-push");
 
// (C) SETUP SERVER
webpush.setVapidDetails("mailto:" + mail, publicKey, privateKey);
const app = express();
app.use(express.static(__dirname)); // SERVE STATIC FILES
app.use(bodyParser.json()); // JSON PARSER

// (D) SERVE TEST HOME PAGE
app.get("/", (req, res) => {
  res.sendFile(path.join(__dirname, "/3-perm-sw.html"));
});
 
// (E) SEND TEST PUSH NOTIFICATION
app.post("/mypush", (req, res) => {
  res.status(201).json({}); // REPLY WITH 201 (CREATED)
  webpush.sendNotification(req.body, JSON.stringify({
    title: "Welcome!",
    body: "Yes, it works!",
    icon: "i-loud.png",
    image: "i-zap.png"
  }))
  .catch((err) => { console.log(err); });
});
 
// (F) START!
app.listen(port, () => {
  console.log(`Server deployed at ${port}`)
});
  1. Server settings, insert both public and private keys here.
  2. Load the required modules. Doh.
  3. Set up the HTTP and push server.
  4. Set express to serve 3-perm-sw.html on http://localhost/
  5. Remember that the subscription object is sent back to this push server? Notice how it is “reused” and “forwarded” in webpush.sendNotification(req.body, NOTIFICATION).
  6. Start the server. Doh.

P.S. In your own project, mypush/ should be a protected “admin only” endpoint. Also, use the absolute URL for the icon and image… Just being lazy here.

 

 

STEP 6) LAUNCH!

All that’s left is to launch the server.

  • Run node 5-server.js.
  • Access http://localhost/ in your browser.
  • Allow the notification.

Congratulations, you have sent out your first push notification.

 

USEFUL BITS & LINKS

That’s all for the tutorial, and here is a small section on some extras and links that may be useful to you.

 

RESTRICTIONS

  • Take note that you will need a valid https:// website for push notifications to work. http://localhost is an exception for testing and development.
  • The same-origin policy applies.
  • If the user is in incognito or privacy mode, the service worker cannot be registered and will fail.

 

I DENIED NOTIFICATION PERMISSION, WHAT DO I DO!?

Yep, once denied, Notification.requestPermission() will not prompt anymore. Click on the site icon in the URL bar, and change the permission manually.

 

HOW DO I IMPLEMENT THIS ON A LIVE SERVER?

It’s a rather complex situation, especially for shared hosting that already runs a web server – Apache, Nginx, IIS, etc… This demo Node push server will clash with the existing web server (both using port 80).

  • Solution 1 – Get your own “dedicated Node JS” hosting or cloud server. No script changes are required.
  • Solution 2 – Tweak the Node push server.
    • Remove app.use(express.static(__dirname)) and the entire app.get("/") section. Let the existing web server deal with HTTP services.
    • Change the port number, for example, to 8080.
    • Optionally, set an HTTP proxy and/or virtual host in the webserver. I.E. Map https://site.com/mypush to https://site.com:8080/mypush. Do your own research on how this works.
  • Solution 3 – Build your own push server. Yep, replace the entire step 5 with a server-side language supported on your server. NodeJS is not the only one capable of running a push server.

 

COMPATIBILITY CHECKS

 

LINKS & REFERENCES

 

THE END

Thank you for reading, and we have come to the end. I hope that it has helped you to better understand, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!

3 thoughts on “Push Notifications With NodeJS (Step-By-Step Example)”

Leave a Comment

Your email address will not be published.