Web PushNotification made simple with webtask.io

You don’t need too much to implement a push notification for your web app. Actually is pretty simple, just follow three steps.

  1. Ask permission for the user
  2. Subscribe the user saving his keys into a database
  3. Create ServiceWorker that will listening for notifications and display-it

After that, you use this keys to send a push notification.
You don’t need anything spectacular, no external service or API to do that.

In this post, I will explain how can we archive this without any database, just HTML/JS and WebTask.io.

You can find the source code on GitHub: https://github.com/Ridermansb/push-notification-when-webhook

Asking user permission

const status = await Notification.requestPermission();

This code will prompt the user if the current webpage can send push notification.

Asking user permission to send push notification

Once the user accept, you need to generate a subscription and save-it to the database, to archive this we need a API and an way to store the subscription.

Create Webtask.io to handle our API and Storage

Create new file called `hook.js` with

const webPush = require('web-push');
const Webtask = require('webtask-tools');
const app = new (require('express'))();
const bodyParser = require('body-parser');

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true,
}));

webPush.setVapidDetails(
'mailto:your@email.com',
process.env.VAPID_PUBLIC,
process.env.VAPID_PRIVATE
);
app.post('/hook', (req, res) => {
// Will fired by WebHook
})
app.post('/subscribe', (req, res) => {
// Will fired when user accept push notification
})

This is a very simple express app with two endpoints
The first one /hook will fired by webhook and push to the all subscription, the second one `/subscribe` will save the subscriptions.

The VAPID_PUBLIC and VAPID_PRIVATE can be retreived by WebPush library using command line bellow:

web-push generate-vapid-keys

Implement subscribe functionality

app.post('/subscribe', (req, res) => {
const { storage } = req.webtaskContext;
const { endpoint, keys } = req.body;

storage.get((errorGet, data) => {
if (errorGet) { return res.send(400); }
if (!data) {
data = { subscriptions: [] }
}

data.subscriptions.push({
titleField: false,
bodyField: false,
sub: {
endpoint,
keys: { p256dh: keys.p256dh, auth: keys.auth },
}
});
storage.set(data, function() {
return res.status(200).json({ ok: true })
});
})
});

Implement push functionality

  1. Lookup all subscription
  2. Send push notifications to these subscriptions
app.post('/hook', (req, res) => {
const { storage } = req.webtaskContext;

storage.get((error, data) => {
if (error) { return res.send(400); }
if (!data) {
data = { subscriptions: [] }
}
const payload = JSON.stringify({
title: 'Hook trigger',
body: 'New hook trigger',
});

const sendPushPromises = data.subscriptions
.map(data => {
webPush.sendNotification(data.sub, payload, { TTL: 3600 })
});
Promise.all(sendPushPromises)
.then(resp => res.json(resp))
.catch(e => res.send(400));
});
});

That’s all we need to do in our Webtask, now we need save the subscription once the user accept. Let’s replace your request Permission code (UI)

const status = await Notification.requestPermission()
if (status === 'granted') {
await this.saveSubscription()
}

And save the subscription

async saveSubscription() {
const reg = await navigator.serviceWorker.ready;
const sub = await reg.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlB64ToUint8Array(VAPID_PUBLIC),
});

subscribe(sub); // Call API with post method
}

So far so good. The last step is listening for notifications

ServiceWorker that listening for notifications

With service worker, we can keep our app running listening for notifications . Just create a new file called sw.js with :

self.addEventListener('push', (event) => {    
const notificationData = event.data.json();
event.waitUntil(
self.registration.showNotification(
notificationData.title, {
body: notificationData.body,
icon: notificationData.icon,
tag: notificationData.tag,
}),
);
}
);

This will listening the push events and display notification when the event is fired.

To register this service worker, just install-it

// Register Service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('./sw.js', { scope: '/' });}
else {
console.warn('Not supported by browser');
}

Publishing our WebTask

wt create hook.js --name myhook -d web-push

This command will create new webtask and return the URL that will be used as API.

Now you only need to put the URL "https://<WEB_TASK_URL>/hook" to your hook and see the magic happens

You can find a live demonstration here.

Sênior Web Developer