Table of Contents
Learning Outcomes
- Learn how to make a basic web notification
- Handling user input in web notifications
- Cloud notification providers
Learning Activities
Basic Web Notifications
Modern browsers have begun including the Notifications API to allow developers an easy way to create basic web push notifications. In this section, we will walk through the steps on how to create and handle a notification.
- index.html
- notifications.js
<!DOCTYPE html> <html> <head> <script src="notifications.js" defer></script> </head> <body> <div id="headerText"> Let's Make a Notification! </div> <input id="permissionButton" type="button" value="Click for permission"> <input id="notificationButton" type="button" value="Click for a push notification"> </body> </html>Opening this file in our browser we get a webpage that looks like this:

Inside of notifications.js, we want to grab a reference to these elements so that we can use them later
let header = document.getElementById("headerText"); let permButton = document.getElementById("permissionButton"); let notifButton = document.getElementById("notificationButton");
permButton.addEventListener('click', () => { let promise = Notification.requestPermission().then((result) => { console.log(result); }); });Now, once we click on the button, a pop-up will appear asking for permission to send notifications. Depending on the user's response, the possible values stored can be 'granted', 'denied', or 'default'.

Here is an example of what that would look like.
const notif = new Notification('Our new notification', {});This creates a new notification, but we currently have no way of triggering this notification to appear. Let's add a listener to this code to connect it to our button.
notifButton.addEventListener('click', () => { const notif = new Notification('Our new notification', {}); });Unfortunately, notifications are not able to show from just a local file and requires a hosted website that uses HTTPS to ensure the notification is sent securely. Because of this, our index.html file will not be able to display a notification unless you are able to host it somewhere like github pages. However to see what it would look like, press the button below.
Depending on whether or not you gave us permission to send notifications, you may or may not have actually seen a notification there. But how did we do that? Before pushing the notification, you should include a check on the Notification.permission that we got from asking permission in Step 2. Here is how we did it:
notifButton.addEventListener('click', () => { if (Notification.permission === "granted") { const notif = new Notification('Our new notification', {}); } });
notifButton.addEventListener('click', () => { if (Notification.permission === "granted") { const notif = new Notification('Our new notification', { icon: "https://cdn-icons-png.flaticon.com/512/2431/2431996.png", body: "A more detailed message about our notification" }); } });To see how our notification has changed, press the button below.
notifButton.addEventListener('click', () => { if (Notification.permission === "granted") { const notif = new Notification('Our new notification', { icon: "https://cdn-icons-png.flaticon.com/512/2431/2431996.png", body: "A more detailed message about our notification" }); notif.addEventListener("click", () => { document.getElementById("headerText").innerText = "You clicked on the notification!"; }); } });By adding this event listener to our button, whenever the notification is clicked on we can make changes accordingly. In our example, this just changes the text on our screen to display that we clicked on the notification. Below is an interactive example that tracks the amount of times you have clicked directly on this notification.
Persistent Notifications
self.oninstall = function() { //creates a new cache with the name parameter caches.open('webNotif').then(function(cache) { //add array of strings of relative paths to files w/in application cache.addAll(['/','index.html']) .then(function() { console.log('cached!'); }).catch((err) => { console.log("Error: " + err); }) }) } self.onactivate = function() { console.log("SW activated"); } self.onfetch = function(event) { event.respondWith( caches.match(event.request) .then(function(response){ if(response){ return response; } else { return fetch(event.request); } }) ) }Note: Service workers only work on HTTPS websites or localhost.
You now need to register your service worker onto your web page with this script:
<script> if(navigator.serviceWorker) { navigator.serviceWorker.register('sw.js'); } </script>
let persistentButton = document.getElementByID("persistentButton"); persistentButton.addEventListener('click', () => { if(Notification.permission === 'granted') { navigator.serviceWorker.ready.then((registration) => { registration.showNotification("Persistent notification up", {body:"The buttons will change the color of the div", actions:[{action:"yellow", title:"yellow", icon:"https://upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Solid_blue.svg/512px-Solid_blue.svg.png?20150316143734"}, {action:'red', title:"red", icon:"https://emojis.wiki/emoji-pics/mozilla/red-circle-mozilla.png"}]}); }); } });To find the max number of actions possible for your browser, you can use Notification.maxActions.
const messageChannel = new MessageChannel(); navigator.serviceWorker.controller.postMessage({ type: 'INIT_PORT' }, [messageChannel.port2]);We then need to save the port into the Service Worker by adding the following in sw.js:
let port; //create an event listener to listen for messages from notification.js self.addEventListener("message", event => { if(event.data && event.data.type === 'INIT_PORT') { port = event.ports[0]; } })With the saved port, we can now send messages from sw.js to notification.js with the "onnotificationclick" event that is only available to service workers.
self.addEventListener("notificationclick",(event) => { //event.action gets the name of the action that you created with showNotification(); if(event.action === 'yellow') { getVersionPort.postMessage({type:"yellowType"}); } else if (event.action === 'red') { getVersionPort.postMessage({type:"redType"}); } })In your notification.js file, you can now create an event listener for receiving messages from sw.js and handle the event accordingly.
messageChannel.port1.onmessage = (event) => { //the inputDiv is an element in the DOM if(event.data.type === "yellowType") { document.getElementById("inputDiv").style.backgroundColor = "yellow"; } else if (event.data.type === "redType") { document.getElementById("inputDiv").style.backgroundColor = "red"; } }The result of all the previous code can be seen below:
Cloud Notifications
For remote notifications through the cloud, we can use Google Firebase Cloud Messaging[10].
First, sign up or log in and click "Go to Console"
Next, create a new project.
Enter a name for the project. For this tutorial, we're going to call it "notifications-tutorial".
When prompted about Google Analytics, select no.
Click "Create Project", and wait for Firebase to create your project for you. This may take several minutes.
After creating the Firebase project, you should be on the project's dashboard. Click the Webapp icon
to register a webapp with your firebase project.
Enter a nickname for the webapp. For this tutorial we'll use "notification-tutorial-webapp". You can
also at this point choose to setup firebase hosting for your website, but for this tutorial we're
going to assume you are hosting your website elsewhere.
Click "Register app".
Select "Use a <script> tag" instead of "Use npm". This allows us to make a simple standalone webapp
that uses the Firebase API rather than depending on Node JS packages. You will be shown an html script
element that imports the Firebase API and initializes the app with your authentication keys. Your
firebaseConfig
will be unique to your webapp, so make sure you hold on to it and use it
when appropriate. Copy this text to your clipboard.
Paste the script element into your html file from earlier. Note that we have added a "defer" attribute
in order to ensure the script loads at the correct time. We're also going to add a new label at the
bottom to display some text later.
<!DOCTYPE html>
<html>
<head>
<script src="_sample_notifications.js" defer></script>
</head>
<body>
<script type="module" defer>
// Import the functions you need from the SDKs you need
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.14.0/firebase-app.js";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Your web app's Firebase configuration
const firebaseConfig = {
//YOUR FIREBASE CONFIG HERE
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
</script>
<div id="headerText"> Let's Make a Notification! </div>
<input id="permissionButton" type="button" value="Click for permission">
<input id="notificationButton" type="button" value="Click for a push notification"> <br>
<label id="tokenLabel"></label>
</body>
</html>
Next, we import the Firebase messaging API and get a messaging
object that allows us to
register our client with Firebase to be able to receive messages.
// Import the functions you need from the SDKs you need
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.14.0/firebase-app.js";
import { getMessaging, getToken, onMessage} from "https://www.gstatic.com/firebasejs/9.14.0/firebase-messaging.js";
...
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const messaging = getMessaging(app);
Going back to our firebase dashboard, now we need to set up a certificate for Web Push Notifications.
Click the cog wheel, click "Project Settings", go to the "Cloud messaging Tab", scroll down and click
"Generate key pair".
A key will then be displayed to you. This key is unique to you so you must copy it and paste it
anywhere [WEB PUSH HERE] is in the example code.
Back in our html, we need to add code to register the client with firebase using the key we just generated. We also need to print the token that we get back so that we can use it to reference our client when we actually send a notification. This code itself also generates a request for notification permissions, so we want to make sure it triggers from the button press instead of automatically.
function register_client() {
//generate token
getToken(messaging, {vapidKey: '[WEB PUSH HERE]'}).then((currentToken) => {
if (currentToken) {
console.log(currentToken)
document.getElementById("tokenLabel").textContent = String(currentToken)
}
}).catch((err) => {
console.log('An error occurred while retrieving token. ', err);
});
}
document.getElementById ("permissionButton").addEventListener("click", register_client, false);
We also need to set up an event handler that actually presents the notification to the user upon receipt from firebase.
//handler for received message
onMessage(messaging, (payload) => {
console.log('Message received. ', payload);
//extract notification payload title and message body
const notificationTitle = payload.notification.title;
const notificationOptions = {
body: payload.notification.body,
};
const notif = new Notification(notificationTitle, notificationOptions);
});
Next we need to create a service worker in a file called firebase-messaging-sw.js in the root directory of our website for firebase to be
able to register with our client. The simplest way to do this involves using the older v8 Firebase API
which works better with being in a separate file. We must be careful to use the same firebaseConfig
that we used earlier in our HTML. This service worker needs to have a dummy event handler for the message
receipt, but it does not actually need to do anything. The handler in our main html will handle the
notification.
// Scripts for firebase and firebase messaging
//This needs to be version **8**.2.0
importScripts("https://www.gstatic.com/firebasejs/8.2.0/firebase-app.js");
importScripts("https://www.gstatic.com/firebasejs/8.2.0/firebase-messaging.js");
// Initialize the Firebase app in the service worker by passing the generated config
const firebaseConfig = {
//YOUR FIREBASE CONFIG HERE
};
firebase.initializeApp(firebaseConfig);
// Initialize firebase messaging
const messaging = firebase.messaging();
messaging.onBackgroundMessage(function(payload) {
//do nothing
});
Additionally, the full html code you should have at this point is
<!DOCTYPE html>
<html>
<head>
<script src="_sample_notifications.js" defer></script>
</head>
<body>
<script type="module" defer>
// Import the functions you need from the SDKs you need
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.14.0/firebase-app.js";
import { getMessaging, getToken, onMessage} from "https://www.gstatic.com/firebasejs/9.14.0/firebase-messaging.js";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Your web app's Firebase configuration
const firebaseConfig = {
//YOUR FIREBASE CONFIG HERE
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const messaging = getMessaging(app);
function register_client() {
//generate token
getToken(messaging, {vapidKey: '[WEB PUSH HERE]'}).then((currentToken) => {
if (currentToken) {
console.log(currentToken)
document.getElementById("tokenLabel").textContent = String(currentToken)
}
}).catch((err) => {
console.log('An error occurred while retrieving token. ', err);
});
}
document.getElementById ("permissionButton").addEventListener("click", register_client, false);
//handler for received message
onMessage(messaging, (payload) => {
console.log('Message received. ', payload);
//extract notification payload title and message body
const notificationTitle = payload.notification.title;
const notificationOptions = {
body: payload.notification.body,
};
const notif = new Notification(notificationTitle, notificationOptions);
});
</script>
<div id="headerText"> Let's Make a Notification! </div>
<input id="permissionButton" type="button" value="Click for permission">
<input id="notificationButton" type="button" value="Click for a push notification"> <br>
<label id="tokenLabel"></label>
</body>
</html>
For Firebase cloud notifications to work, the website must be served to the browser using HTTPS rather than HTTP. This means you will either need to deploy the code to a secured web host or have a local self signed server, which is outside of the scope of this tutorial.
Once your website is deployed, visit it with a supported browser (Chrome works best) and click the
"Click for permission" button. If all went well you will see a label appear beneath the button with the
Firebase token identifying your device. Copy this token and hold on to it.
Return to your firebase project dashboard. Enter the messaging pane and click "Create your first campaign".
Select "Firebase Notification messages" in the pop-up box.
In the notification page, enter in a title and message body for your notification. Then, click "Send test message".
In the pop up, paste the client token you saved a few steps earlier and click the "+".
Click "Test". If all goes well, you should receive a notification on your client with your specified notification title and body text!
If you want to see a working version of this, one is deployed at https://notifications-tutorial-18861.web.app/
Standards
The main standard for push notifications is requesting permission from the user to allow your website to send notifications. MDN outlines that "Before an app can send a notification, the user must grant the application the right to do so" [1]. Furthermore, they discuss how push notifications had been abused in the past and that one of the new countermeasures against that is to only request permission after the user gestures in some way that they may want these notifications, for example, clicking a button that says 'Keep Me Notified'. Once permission has been asked for, every notification should check to ensure that the current permission status is 'granted'.
History
Web push notifications are a relatively new innovation to the web development scene, making their history not span a very long way back in time. The first predecessor to notifications through the web is email communication in which websites and companies can send mass emails to all of their users giving an update on whatever it is they desire. In their article What are Push Notificiations - The Ultimate Guide, Gravitec states that "In 2001, RIM created the first email alert system" [6]. This was the first appearance of any type of push notification system, and started out as a functionality for the email app that was only on blackberry phones. Todd Grennan highlights that web push stems off of the idea of mobile push, which originated back in 2009 with the rise of smart phones, however historically web notifications have had a much harder time of being widely used and accepted. This reluctance of integration mainly comes from users not trusting web notifications as much as mobile push notifications, causing a large percent of people to decline websites the permissions necessary [7]. The first addition of web push notifications to browsers came in 2014 as Google added this functionality into Google Chrome. Slowly, thoroughout the next 4 years or so browsers such as Opera, Firefox, Safari, and Edge begin to support this functionality [8].
Our Opinion
As technology becomes more and more integrated into everyones daily life, more and more users will begin getting comfortable with the conceptof web push and help it to grow into a mainstream feature on many websites. We think that this is overall a positive for both web developers and web users. On the side of the web devs, push notifications help to retain visitors and keep people coming back to your site, as well as providing a distinct advantage to marketing by allowing you direct access to the customers [9]. These benefits can lead to more revenue on your site and help to push your site more into the mainstream attention. As for the web users, more websites utilizing push notifications can help to build you a more customized experience on the website, "based on both [your] own preferences as well as historical click behaviour" [9]. With this, users will see more of the content that they would like to see and have it all delivered directly to them through notifications.
Reference List
-
[1]
MDN. Using the notifications API. Web APIs | MDN. Last retrieved November 17, 2022,
from https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API/Using_the_Notifications_API -
[2]
MDN. Notification. Web APIs | MDN. Last retrieved November 17, 2022,
from https://developer.mozilla.org/en-US/docs/Web/API/notification#instance_properties -
[3]
Bourlon, C. (2019, May 4). Write Your First Service Worker
Last retrieved November 18, 2022, from https://www.youtube.com/watch?v=5JAZcSQ2u1I -
[4]
MDN. ServiceWorkerRegistration.showNotification() | MDN. Last retrieved November 18, 2022,
from https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/showNotification -
[5]
Gerschau, F. How to communicate with Service Workers. Last retrieved November 18, 2022,
from https://felixgerschau.com/how-to-communicate-with-service-workers/ -
[6]
Gravitec. (2019, May 4). What are Push Notifications - The Ultimate Guide. Gravitec.
Last retrieved November 16, 2022, from https://gravitec.net/blog/what-are-push-notifications/ -
[7]
Grennan, T. (2020, January 31). Behind web push notifications: All You Need To Know About Web Messaging's Secret Weapon'. Braze.
Last retrieved November 15, 2022, from https://www.braze.com/resources/articles/behind-web-push-notifications -
[8]
Grennan, T. (2020, January 31). Behind web push notifications: History of web push. Braze.
Last retrieved November 15, 2022, from https://www.braze.com/resources/articles/behind-web-push-notifications-2 -
[9]
Valdez, L. (2022, March 2). 5 Benefits of Web Push Notifications. Freestar.
Last retrieved November 18, 2022, from https://freestar.com/web-push-notifications-benefits/ -
[10]
(2022, Nov 17). Firebase Cloud Messaging. Firebase.
Last retrieved November 19, 2022, from https://firebase.google.com/docs/cloud-messaging -
[11]
(2022, Nov 17). Set up a JavaScript Firebase Cloud Messaging client app. Firebase.
Last retrieved November 19, 2022, from https://firebase.google.com/docs/cloud-messaging/js/client -
[12]
(2022, Nov 17). Send a test message to a backgrounded app. Firebase.
Last retrieved November 19, 2022, from https://firebase.google.com/docs/cloud-messaging/js/first-message -
[13]
(2022, Nov 17). Receive messages in a JavaScript client. Firebase.
Last retrieved November 19, 2022, from https://firebase.google.com/docs/cloud-messaging/js/receive#web-version-8_2 -
[14]
(2022, Nov 17). Add Firebase to your JavaScript project. Firebase.
Last retrieved November 19, 2022, from https://firebase.google.com/docs/web/setup