This feature is not (yet) supported on your device
This feature is only available on installed web apps
This page was opened declaratively through the navigate property of the options for
.showNotification().
This page was opened through the OK action of the notification which is specified using the
navigate property of the action object in the actions array for
.showNotification().
The Push API and Notifications API enable web apps to receive and display push notifications from a server, even
when the app is in the background or not running at all.
Demo
Click the "Subscribe" button below to subscribe to notifications. Once subscribed, you will send a notification to
yourself by filling out the form below. You can specify a delay in seconds so you can schedule a notification and
close the app in the meantime to check it is delivered while the app is not running.
The "require interaction" checkbox will make the notification persistent on supporting devices, which means it will
not disappear until the user interacts with it.
When you click or tap the notification, this page will be opened, even if the PWA is not running. If the PWA is
running, the notificationclick event handler will be triggered, unless the navigate
property is set in the options for .showNotification(). In that case, this page will also be opened and
it will indicate that it was opened through the navigate property, but the notificationclick
event handler will not be triggered.
You can send a notification through the form below.
const registration = await navigator.serviceWorker.getRegistration();
const base64UrlToUint8Array = base64UrlData => {
const padding = '='.repeat((4 - base64UrlData.length % 4) % 4);
const base64 = (base64UrlData + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
const rawData = atob(base64);
const buffer = new Uint8Array(rawData.length);
for(let i = 0; i < rawData.length; ++i) {
buffer[i] = rawData.charCodeAt(i);
}
return buffer;
};
const subscribeToPushMessages = async (registration, publicKey) => registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: base64UrlToUint8Array(publicKey)
});
const unsubscribeFromPushMessages = subscription => subscription.unsubscribe();
const getPushSubscription = () => registration.pushManager.getSubscription();
const apiUrl = '...';
const sendPushMessage = async ({title, message, delay, interaction}) => {
const pushSubscription = await getPushSubscription();
const delayTime = !Number.isInteger(parseInt(delay, 10)) ? 0 :
delay > 5 ? 5 : delay;
fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
pushSubscription,
title,
message,
delay: delayTime * 1000,
interaction
})
});
};
// in service worker
// triggered when the notification arrives
self.addEventListener('push', async e => {
const data = e.data.json();
const {title, message, interaction, url} = data;
const options = {
body: message,
icon: '/src/img/icons/icon-512x512.png',
vibrate: [100, 50, 100],
data: {
dateOfArrival: Date.now()
},
actions: [
{
action: 'confirm',
title: 'OK',
// when the OK action is chosen from the options
// in the notification, this URL will
// be navigated to and the "notificationclick"
// event handler will not be triggered
navigate: url
},
{
action: 'close',
title: 'Close notification'
},
],
// when the notification is clicked, this URL will
// be navigated to and the "notificationclick" event
// handler will not be triggered
navigate: url,
requireInteraction: interaction
};
e.waitUntil(
self.registration.showNotification(title, options)
.then(hasActiveClients)
.then((activeClients) => {
if(!activeClients) {
self.numBadges += 1;
navigator.setAppBadge(self.numBadges);
}
})
.catch(err => sendMessage(err))
)
});
// navigate to the URL when the notification is clicked
// when the "navigate" property is set in the options for
// .showNotification(), that URL will be navigated to when
// the notification is clicked and this handler will be ignored
self.addEventListener('notificationclick', async (e) => {
const {notification, action} = e;
const {data} = notification;
notification.close();
if(action === 'close') {
return;
}
e.waitUntil(clients.openWindow(data.url))
});