How to send notifications to the browser (wep push) using Node.js and Service Workers

Today I will teach you how to create web notifications from our Node - Express.js server to an HTML web application, the notifications will be created from the API provided by the browser, we will use a module called web push ( web-push ) that will help us create them, additionally we will use what is called Service workers ( processes that are kept running from the browser) |
NODE.js
We will start by creating a folder on our desktop web-notification-app-node /
and activating the console of our favorite code editor, and we will install the following dependencies:
npm init --yes
npm i express morgan dotenv web-push
We will create a file called .env where we will place our public and private keys provided by the web-push module
.env
PUBLIC_KEY = tu_public_key_here
PRIVATE_KEY = you_private_key_here
Once our environment variables file is created, we proceed to generate these keys, for this we will write the following in the console
npx web-push generate-vapid-keys
This will return something like

Those keys are the ones that we will place in the .env file
We will create a file called webpush.js
with the following configuration
src / webpush.js
const webpush = require ('web-push')
webpush.setVapidDetails (
`mailto: $ {process.env.EMAIL}`,
process.env.PUBLIC_KEY,
process.env.PRIVATE_KEY
);
module.exports = webpush
src / index.js
require ('dotenv'). config ()
const express = require ('express')
const morgan = require ('morgan')
const path = require ('path')
const app = express ()
// MIDDLEWARES
app.use (morgan ('dev'))
app.use (express.urlencoded ({extended: false}))
app.use (express.json ())
// ROUTES
app.use (require ('./ routes /'))
// STATICS FILES
app.use (express.static (path.join (__ dirname, 'public')))
app.listen (process.env.PORT || 3000, () => console.log ('Server on port', process.env.PORT || 3000))
We create a folder
routes/
and inside an index.js file with our 2 routes routes / index.js
const {Router} = require ('express')
const router = Router ()
const webpush = require ('../ webpush')
let pushSubscripton;
router.post ('/ subscribeUser', async (req, res) => {
pushSubscripton = req.body;
res.status (200) .json ();
})
router.post ('/ new-msg', async (req, res) => {
const {title, message} = req.body;
const payload = JSON.stringify ({
title,
message
});
res.status (200) .json ();
try {
await webpush.sendNotification (pushSubscripton, payload);
} catch (error) {
console.log (error);
}
})
module.exports = router
We will create a
public /
folder and inside a file index.html, main.js and serviceWorker.js public / index.html
<! DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<meta http-equiv = "X-UA-Compatible" content = "IE = edge">
<meta name = "viewport" content = "width = device-width, initial-scale = 1.0">
<title> How to send notifications to the browser (wep push) using Node.js and Service Workers </title>
<link href = "https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel = "stylesheet"
integrity = "sha384-BmbxuPwQa2lc / FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH / Ev + nYRRuWlolflfl" crossorigin = "anonymous">
</head>
<body>
<div class = "container mt-5 mb-2">
<h2> How to send notifications to the browser (wep push) using Node.js and Service Workers - <code> <a href="https://hive.blog/@jfdesousa7"> Jfdesousa7 </a> </code> </h2>
<div class = "col-md-4 mt-5 mx-auto">
<div class = "card">
<div class = "card-body">
<form id = "form">
<div class = "mb-4">
<input type = "text" id = "title" placeholder = "Enter the title of the message"
class = "form-control" autofocus>
</div>
<div class = "mb-4">
<textarea class = "form-control" id = "message" rows = "2"
placeholder = "Enter the message"> </textarea>
</div>
<div class = "mb-4>
<button type = "submit" class = "btn btn-primary"> Send notification </button>
</div>
</form>
</div>
</div>
</div>
</div>
<script src = "./ main.js"> </script>
</body>
</html>
public / main.js
const PUBLIC_KEY = "BPU1qVu0bNbIFdC15E4EooVBhjuOV8w40rk5NO3xR-UtF_3I7l5h5EQxeT2yXvEBS4ArrUfE7-YfKEPoLAYVi9k";
async function subscribeUser () {
const register = await navigator.serviceWorker.register ("/ serviceWorker.js", {
scope: "/",
});
const subscribe = await register.pushManager.subscribe ({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array (PUBLIC_KEY),
});
await fetch ("/ subscribeUser", {
method: "POST",
body: JSON.stringify (subscribe),
headers: {
"Content-Type": "application / json",
},
});
console.log ("Subscribed!");
}
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;
};
const form = document.querySelector ('# form')
const title = document.querySelector ('# title')
const message = document.querySelector ('# message')
form.addEventListener ('submit', async (e) => {
e.preventDefault ()
await fetch ('/ new-msg', {
method: "POST",
body: JSON.stringify ({
title: title.value,
message: message.value
}),
headers: {
"Content-Type": "application / json"
}
})
form.reset ()
})
subscribeUser ();
public / serviceWorker.js
self.addEventListener ("push", (e) => {
const data = e.data.json ();
self.registration.showNotification (data.title, {
body: data.message,
icon: "./images/jfdesousa7.png",
});
});
Once we run our example with node src / index.js
we must allow the browser to send notifications


And with those friends we reached the end of the tutorial, I hope you enjoyed it and until next time! |
Steem Sri Lanka Discord Channel
✵✵✵✵✵✵✵✵✵✵✵✵✵✵✵✵✵✵✵✵✵✵✵✵✵✵✵✵✵