This codelab is part of the Developing Progressive Web Apps training course, developed by the Google Developers Training team. You will get the most value out of this course if you work through the codelabs in sequence.
For complete details about the course, see the Developing Progressive Web Apps overview.
Introduction
This lab shows you the basics of sending, receiving, and displaying push notifications. Notifications are messages that display on a user's device, outside of the context of the browser or app. Push notifications are notifications created in response to a message from a server, and work even when the user is not actively using your application. The notification system is built on top of the Service Worker API, which receives push messages in the background and relays them to your application.
What you'll learn
- How to create and display a notification in a web application, with and without user-required actions
- How to use the Web Push API to receive notifications
- How to follow best practices when designing push notifications in your app
What you should know
- Have completed the Service Worker module or have equivalent experience with Service Worker
- Have completed the Promises lab or have equivalent experience
- Intermediate experience using the command line interface
- Intermediate-to-advanced experience with JavaScript
What you will need
- Computer with terminal/shell access
- Connection to the Internet
- A Google or Gmail account
- A browser that supports web push
- Node and npm
Download or clone the pwa-training-labs repository from github and install the LTS version of Node.js, if needed.
Open your computer's command line. Navigate into the push-notification-lab/app/
directory and start a local development server:
cd push-notification-lab/app npm install node server.js
You can terminate the server at any time with Ctrl-c
.
npm install
reads the dependencies in package.json
and installs the web-push
module for Node.js, which we will use in the second half of the lab to push a message to our app. The express
module is also installed, which is used by the development server (server.js
).
Open your browser and navigate localhost:8081/
.
Note: Unregister any service workers and clear all service worker caches for localhost so that they do not interfere with the lab. In Chrome DevTools, you can achieve this by clicking Clear site data from the Clear storage section of the Application tab.
Open the push-notification-lab/app/
folder in your preferred text editor. The app/
folder is where you will be building the lab.
This folder contains:
images/
folder contains sample imagesjs/main.js
is the main JavaScript for the app, and where you will write the app's codenode/main.js
is the Node.js serversamples/
folder contains sample landing pagesindex.html
is the main HTML page for our sample site/applicationmanifest.json
is the Firebase manifest filepackage.json
&package-lock.json
keep track of app dependenciesserver.js
is a local development server for testingsw.js
is the service worker file where we will write the script to handle notifications
Push notifications are assembled using two APIs: the Notifications API and the Push API. The Notifications API lets us display system notifications to the user. We'll explore the Push API in section 3.
Check for support
Because notifications are not yet fully supported by all browsers, we must check for support.
Replace TODO 2.1 in js/main.js
with the following code:
if (!('Notification' in window)) {
console.log('This browser does not support notifications!');
return;
}
Note: In a practical application we would perform some logic to compensate for lack of support, but for our purposes we can log an error and return.
Request permission
Before we can show notifications, we must get permission from the user.
Replace TODO 2.2 in js/main.js
with the following code:
Notification.requestPermission(status => {
console.log('Notification permission status:', status);
});
Let's test this function in the browser. Save the code and refresh the page in the browser. A message box should appear at the top of the browser window prompting you to allow notifications.
If the prompt does not appear, you can set the permissions manually by clicking the Information icon in the URL bar. As an experiment, try rejecting permission and then check the console. Now reload the page and this time allow notifications. You should see a permission status of "granted" in the console.
Explanation
The requestPermission
method opens a popup when the user first lands on the page prompting them to allow or block notifications. Once the user accepts, you can display a notification. This permission status is stored in the browser, so calling this again returns the user's last choice.
Note: In production, requesting permissions on page load is a poor user experience. Rather, permissions are better requested when a user opts into a specific feature that requires some permission.
Display the notification
Replace TODO 2.3 in js/main.js
in the displayNotification()
function with the following code:
if (Notification.permission == 'granted') {
navigator.serviceWorker.getRegistration().then(reg => {
// TODO 2.4 - Add 'options' object to configure the notification
reg.showNotification('Hello world!');
});
}
Save the file and reload the page in the browser. Click allow on the permission pop-up if needed. Now if you click Notify me! you should see a notification appear!
Note: Notifications may not surface if you're in full screen mode.
For more information
Add notification options
The notification can do much more than just display a title.
Replace TODO 2.4 in js/main.js
with an options object:
const options = {
body: 'First notification!',
icon: 'images/notification-flat.png',
vibrate: [100, 50, 100],
data: {
dateOfArrival: Date.now(),
primaryKey: 1
},
// TODO 2.5 - add actions to the notification
// TODO 5.1 - add a tag to the notification
};
Be sure to add the options object to the second parameter of showNotification
:
reg.showNotification('Hello world!', options);
Save the code and reload the page in the browser. Click Notify me! In the browser to see the new additions to the notification.
Explanation
showNotification
has an optional second parameter that takes an object containing various configuration options. See the reference on MDN for more information on each option.
Attaching data to the notification when you create it lets your app get that data back at some point in the future. Because notifications are created and live asynchronously with respect to the browser, you will often want to inspect the notification object after the user interacts with it, to determine what action to take. In practice, we can use a "key" (unique) property in the data to determine which notification was called. We will see how to use a key in a later step.
Add notification actions
To create a notification with a set of custom actions, we can add an actions array inside our notification options object.
Replace TODO 2.5 in the options object in js/main.js
with the following code:
actions: [
{action: 'explore', title: 'Go to the site',
icon: 'images/checkmark.png'},
{action: 'close', title: 'Close the notification',
icon: 'images/xmark.png'},
]
Save the code and reload the page in the browser. Click Notify me! on the page to display a notification. If you're using Chrome, the notification now has two new buttons to click. These don't do anything yet. In the next sections we'll write the code to handle notification events and actions.
Note: On desktop, you may need to hover over the notification to see the actions display.
Explanation
The actions array contains a set of action objects that define the buttons that we want to show to the user. Actions get an ID (the action
property) when they are defined so that we can tell them apart in the service worker. We can also specify the display text (title
), and add an optional image (icon
).
Handle the notificationclose
event
When the user closes a notification, a notificationclose
event is triggered in the service worker.
Replace TODO 2.6 in sw.js
with an event listener for the notificationclose
event:
self.addEventListener('notificationclose', event => {
const notification = event.notification;
const primaryKey = notification.data.primaryKey;
console.log('Closed notification: ' + primaryKey);
});
Save the code and update the service worker in the browser. Now, in the page, click Notify me! and then close the notification (use the default close button, not the "Close the notification" action we created earlier, which doesn't yet have functionality). Check the console to see the log message appear when the notification closes.
Explanation
This code gets the notification object and its data from the event. This data can be anything we like. In this case, we get the value of the primaryKey
property.
Note: The notificationclose
event is a great place to add Google analytics to see how often users are closing our notifications. You can learn more about this in the Google Analytics lab.
Handle the notificationclick event
When the user clicks on a notification or notification action, a notificationclick
event is triggered in the service worker.
Replace the TODO 2.7 in sw.js
with the following code:
self.addEventListener('notificationclick', event => {
// TODO 2.8 - change the code to open a custom page
clients.openWindow('https://google.com');
});
Save the code and reload the page. Update the service worker in the browser. Click Notify me! to create a new notification and click it. You should land on the Google homepage.
Optional: Open a custom page from the notification
To complete TODO 2.8 inside the notificationclick
event, write the code to complete the following tasks (hint: see the notificationclose
event handler).
- Get the notification from the event object and assign it to a variable called "notification".
- Then get the
primaryKey
from the data in the notification and assign it to aprimaryKey
variable. - Replace the URL in
clients.openWindow
with'samples/page' + primaryKey + '.html'
. - Finally, at the bottom of the listener, add a line to close the notification. Refer to the Methods section in the Notification article on MDN to see how to programmatically close the notification.
Save the code and update the service worker in the browser. Click Notify me! to create a new notification and then click the notification. It should take you to page1.html
and the notification should close after it is clicked. Try changing the primaryKey
in main.js
to 2 and test it again. This should take you to page2.html
when you click the notification.
Handle actions
Let's add some code to the service worker to handle the actions.
Replace the entire notificationclick
event listener in sw.js
with the following code:
self.addEventListener('notificationclick', event => {
const notification = event.notification;
const primaryKey = notification.data.primaryKey;
const action = event.action;
if (action === 'close') {
notification.close();
} else {
clients.openWindow('samples/page' + primaryKey + '.html');
notification.close();
}
// TODO 5.3 - close all notifications when one is clicked
});
Save the code and update the service worker in the browser. Click Notify me! to create a new notification. Try clicking the actions.
Note: Notice we check for the "close" action first and handle the "explore" action in an else
block. This is a best practice as not every platform supports action buttons, and not every platform displays all your actions. Handling actions in this way provides a default experience that works everywhere.
Solution code
The solution code for the steps so far can be found in the 02-9-handle-events/
directory.
The Push API is an interface that lets your app subscribe to a push service and enables the service worker to receive push messages.
For more information
Handle the push event
If a browser that supports push messages receives one, it registers a push
event in the service worker.
Inside sw.js
replace TODO 3.1 with the code to handle push events:
self.addEventListener('push', event => {
const options = {
body: 'This notification was generated from a push!',
icon: 'images/notification-flat.png',
vibrate: [100, 50, 100],
data: {
dateOfArrival: Date.now(),
primaryKey: 1
},
actions: [
{action: 'explore', title: 'Go to the site',
icon: 'images/checkmark.png'},
{action: 'close', title: 'Close the notification',
icon: 'images/xmark.png'},
]
};
event.waitUntil(
self.registration.showNotification('Push Notification', options)
);
});
Save the code and update the service worker. Try sending a push message from the browser to your service worker. A notification should appear on your screen.
Note: Push notifications are not currently supported in all browsers. See the entry for "push" on caniuse.com for the latest browser support status.
Explanation
This event handler displays a notification similar to the ones we've seen before. One important note is that the notification creation is wrapped in an event.waitUntil
function. This extends the lifetime of the push event until the showNotification
Promise resolves.
For more information
Create a project on Firebase
To subscribe to the push service in Chrome, we need to create a project on Firebase.
Note: If you are using Firefox, you can skip this step and continue to step 3.3.
Note: Recent changes to Firebase Cloud Messaging let developers avoid creating a Firebase account if the VAPID protocol is used. See the section on VAPID for more information.
- In the Firebase console, select Create New Project.
- Supply a project name and click Create Project.
- Click the Settings icon (next to your project name in the Navigation panel), and select Project Settings.
- Open the Cloud Messaging tab. You can find your Server key and Sender ID in this page. Save these values.
Replace YOUR_SENDER_ID
in the code below with the Sender ID of your project on Firebase and paste it into manifest.json
(replace any code already there):
{
"name": "Push Notifications lab",
"gcm_sender_id": "YOUR_SENDER_ID"
}
Explanation
Chrome uses Firebase Cloud Messaging (FCM) to route its push messages. All push messages are sent to FCM, and then FCM passes them to the correct client.
Note: FCM has replaced Google Cloud Messaging (GCM). Some of the code to push messages to Chrome still contains references to GCM. These references are correct and work for both GCM and FCM.
Get the subscription object
Whenever the user opens the app, check for the subscription object and update the server and UI.
Replace TODO 3.3a in the service worker registration code at the bottom of js/main.js
with the following function call:
initializeUI();
Replace TODO 3.3b in the initializeUI()
function in js/main.js
with the following code:
pushButton.addEventListener('click', () => {
pushButton.disabled = true;
if (isSubscribed) {
unsubscribeUser();
} else {
subscribeUser();
}
});
swRegistration.pushManager.getSubscription()
.then(subscription => {
isSubscribed = (subscription !== null);
updateSubscriptionOnServer(subscription);
if (isSubscribed) {
console.log('User IS subscribed.');
} else {
console.log('User is NOT subscribed.');
}
updateBtn();
});
Save the code.
Explanation
Here we add a click event listener to the Enable Push Messaging button in the page. The button calls unsubscribeUser()
if the user is already subscribed, and subscribeUser()
if they are not yet subscribed.
We then get the latest subscription object from the pushManager
. In a production app, this is where we would update the subscription object for this user on the server. For the purposes of this lab, updateSubscriptionOnServer()
simply posts the subscription object to the page so we can use it later. updateBtn()
updates the text content of the Enable Push Messaging button to reflect the current subscription status. You'll need to use these functions later, so make sure you understand them before continuing.
Subscribe to the push service
Before sending any data via a push message, you must first subscribe to the browser's push service.
Replace TODO 3.4 in js/main.js
with the following code:
swRegistration.pushManager.subscribe({
userVisibleOnly: true
})
.then(subscription => {
console.log('User is subscribed:', subscription);
updateSubscriptionOnServer(subscription);
isSubscribed = true;
updateBtn();
})
.catch(err => {
if (Notification.permission === 'denied') {
console.warn('Permission for notifications was denied');
} else {
console.error('Failed to subscribe the user: ', err);
}
updateBtn();
});
Save the code and refresh the page. Click Enable Push Messaging. The subscription object should display on the page. The subscription object contains the endpoint URL, which is where we send the push messages for that user, and the keys needed to encrypt the message payload. We use these in the next sections to send a push message.
Explanation
Here we subscribe to the pushManager
. In production, we would then update the subscription object on the server.
The .catch
handles the case in which the user has denied permission for notifications. We might then update our app with some logic to send messages to the user in some other way.
Note: We are setting the userVisibleOnly
option to true
in the subscribe method. By setting this to true
, we ensure that every incoming message has a matching notification. The default setting is false
. Setting this option to true
is required in Chrome.
For more information
Unsubscribe from the push service
Let's give users the ability to opt-out of the push subscription.
Replace TODO 3.5 in js/main.js
with the following code:
swRegistration.pushManager.getSubscription()
.then(subscription => {
if (subscription) {
return subscription.unsubscribe();
}
})
.catch(err => {
console.log('Error unsubscribing', err);
})
.then(() => {
updateSubscriptionOnServer(null);
console.log('User is unsubscribed');
isSubscribed = false;
updateBtn();
});
Save the code and refresh the page in the browser. Click Disable Push Messaging in the page. The subscription object should disappear and the console should display User is unsubscribed
.
Explanation
Here we unsubscribe from the push service and then "update the server" with a null
subscription object. We then update the page UI to show that the user is no longer subscribed to push notifications.
For more information
Optional: Send your first web push message using cURL
Let's use cURL to test pushing a message to our app.
Note: Windows machines do not come with cURL preinstalled. If you are using Windows, you can skip this step.
In the browser, click Enable Push Messaging and copy the endpoint URL.
Open a new command window at push-notification-lab/app/
(press Cmd + T
or Ctrl + T
in the command window).
If you are using Chrome, execute the following cURL command in the command window, with your copied ENDPOINT_URL
and your SERVER_KEY
:
curl "ENDPOINT_URL" --request POST --header "TTL: 60" --header "Content-Length: 0" --header "Authorization: key=SERVER_KEY"
Note: The Firebase Cloud Messaging server key can be found in your project on Firebase by clicking the Settings icon in the Navigation panel, clicking Project settings and then opening the Cloud messaging tab.
Here is an example of what the cURL should look like:
curl "https://android.googleapis.com/gcm/send/fYFVeJQJ2CY:APA91bGrFGRmy-sY6NaF8atX11K0bKUUNXLVzkomGJFcP-lvne78UzYeE91IvWMxU2hBAUJkFlBVdYDkcwLG8vO8cYV0X3Wgvv6MbVodUfc0gls7HZcwJL4LFxjg0y0-ksEhKjpeFC5P" --request POST --header "TTL: 60" --header "Content-Length: 0" --header "Authorization: key=AAAANVIuLLA:APA91bFVym0UAy836uQh-__S8sFDX0_MN38aZaxGR2TsdbVgPeFxhZH0vXw_-E99y9UIczxPGHE1XC1CHXen5KPJlEASJ5bAnTUNMOzvrxsGuZFAX1_ZB-ejqBwaIo24RUU5QQkLQb9IBUFwLKCvaUH9tzOl9mPhFw"
You can send a message to Firefox's push service by opening the app in Firefox, getting the endpoint URL, and executing the same cURL without the Authorization
header.
Note: Remember to unregister the previous service worker at localhost if it exists.
curl "ENDPOINT_URL" --request POST --header "TTL: 60" --header "Content-Length: 0"
That's it! We have sent our very first push message. A notification should have popped up on your screen.
Explanation
We are using the Web Push protocol to send a push message to the endpoint URL, which contains the address for the browser's Push Service and the information needed for the push service to send the push message to the right client. For Firebase Cloud Messaging specifically, we must include the Firebase Cloud Messaging server key in a header (when not using VAPID). We do not need to encrypt a message that doesn't contain a payload.
For more information
Get data from the push message
Chrome and Firefox support the ability to deliver data directly to your service worker using a push message.
Replace the push
event listener in sw.js
with the following code to get the data from the message:
self.addEventListener('push', event => {
let body;
if (event.data) {
body = event.data.text();
} else {
body = 'Default body';
}
const options = {
body: body,
icon: 'images/notification-flat.png',
vibrate: [100, 50, 100],
data: {
dateOfArrival: Date.now(),
primaryKey: 1
},
actions: [
{action: 'explore', title: 'Go to the site',
icon: 'images/checkmark.png'},
{action: 'close', title: 'Close the notification',
icon: 'images/xmark.png'},
]
};
event.waitUntil(
self.registration.showNotification('Push Notification', options)
);
});
Save the code.
Explanation
In this example, we're getting the data payload as text and setting it as the body of the notification.
We've now created everything necessary to handle the notifications in the client, but we have not yet sent the data from our server. That comes next.
For more information
Push the message from a Node.js server
We can get all the information we need to send the push message to the right push service (and from there to the right client) from the subscription object.
There are a few things you must do for this step to work:
- Paste the code below into
node/main.js
- Make sure you have saved the changes you made to the service worker in the last step and then update the service worker in the browser by unregistering the previous service worker and refreshing the page.
- Then, click Enable Push Messaging and copy the whole subscription object.
- Replace
YOUR_SUBSCRIPTION_OBJECT
in the code you just pasted intonode/main.js
with the subscription object. - If you are working in Chrome, replace
YOUR_SERVER_KEY
in theoptions
object with your own Server Key from your project on Firebase. Do not overwrite the single quotes. - If you are working in Firefox, you can delete the
gcmAPIKey
option.
const webPush = require('web-push');
const pushSubscription = YOUR_SUBSCRIPTION_OBJECT;
// TODO 4.3a - include VAPID keys
const payload = 'Here is a payload!';
const options = {
gcmAPIKey: 'YOUR_SERVER_KEY',
TTL: 60,
// TODO 4.3b - add VAPID details
};
webPush.sendNotification(
pushSubscription,
payload,
options
);
Save the code. From the push-notification-lab/app/
directory, run the command below:
node node/main.js
A push notification should pop up on the screen. It may take a few seconds to appear.
Explanation
We are using the web-push library for Node.js to simplify the syntax for sending a message to the push service. This library takes care of encrypting the message with the public encryption key. The code we added to node/main.js
configures the server key (for Chrome), payload, and push subscription. These configuration options are then passed to the sendNotification
method.
For more information
Solution code
The solution code can be found in the 03-8-payload/
directory.
Let's use the VAPID protocol to identify the app for the push service. This lets the push service contact you if anything goes wrong with the service, and eliminates the need for a Firebase account in Chrome.
Generate the keys
First, let's install the web-push library globally so we can use it from the command line.
Run the following command:
npm install web-push -g
Now generate public and private keys by entering the following command into a command window at the project/
directory:
web-push generate-vapid-keys [--json]
This generates a public/private key pair. The output should look like this:
======================================= Public Key: BAdXhdGDgXJeJadxabiFhmlTyF17HrCsfyIj3XEhg1j-RmT2wXU3lHiBqPSKSotvtfejZlAaPywJ9E-7AxXQBj4 Private Key: VCgMIYe2BnuNA4iCfR94hA6pLPT3u3ES1n1xOTrmyLw =======================================
Copy your keys and save them somewhere safe. Use these keys for all future messages you send.
Note: The keys are URL Safe Base64 encoded strings.
Subscribe with the public key
In order for VAPID to work we must pass the public key to the subscribe
method as a Uint8Array
. We have included a helper function to convert the public key to this format.
Replace TODO 4.2a in js/main.js
, with the following code with your VAPID public key substituted in:
const applicationServerPublicKey = 'YOUR_VAPID_PUBLIC_KEY';
Replace the subscribeUser()
function in js/main.js
with the code below:
function subscribeUser() {
const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
swRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: applicationServerKey
})
.then(subscription => {
console.log('User is subscribed:', subscription);
updateSubscriptionOnServer(subscription);
isSubscribed = true;
updateBtn();
})
.catch(err => {
if (Notification.permission === 'denied') {
console.warn('Permission for notifications was denied');
} else {
console.error('Failed to subscribe the user: ', err);
}
updateBtn();
});
}
Save the code. In the browser, click Disable Push Messaging or unregister the service worker. Then refresh the page and click Enable Push Messaging. If you are using Chrome, the endpoint URL domain should now be fcm.googleapis.com.
Sign and send the request
Copy the new subscription object and overwrite the old subscription object assigned to the pushSubscription
variable in node/main.js
.
Replace TODO 4.3a in node/main.js
with the following code, with your values for the public and private keys substituted in:
const vapidPublicKey = 'YOUR_VAPID_PUBLIC_KEY';
const vapidPrivateKey = 'YOUR_VAPID_PRIVATE_KEY';
Next, replace TODO 4.3b in the options
object with the following code containing the required details for the request signing. You'll need to replace YOUR_EMAIL_ADDRESS
in the subject
property with your actual email:
vapidDetails: {
subject: 'mailto: YOUR_EMAIL_ADDRESS',
publicKey: vapidPublicKey,
privateKey: vapidPrivateKey
}
Comment out the gcmAPIKey
in the options object (it's no longer necessary):
// gcmAPIKey: 'YOUR_SERVER_KEY',
Save the file. Enter the following command in a command window at the working directory (push-notification-lab/app/
):
node node/main.js
A push notification should pop up on the screen. It may take a few seconds to appear.
Explanation
Both Chrome and Firefox support the The Voluntary Application Server Identification for Web Push (VAPID) protocol for the identification of your service.
The web-push library makes using VAPID relatively simple, but the process is a bit more involved behind the scenes. For a full explanation of VAPID, see the links below.
For more information
Solution code
The solution code can be found in the 04-3-vapid/
directory.
Manage the number of notifications
To complete TODO 5.1 in js/main.js
in the displayNotification
function, give the notification a tag
attribute of 'id1'
.
Save the code and refresh the page in the browser. Click Notify me! multiple times. The notifications should replace themselves instead of creating new notifications.
Explanation
Whenever you create a notification with a tag and there is already a notification with the same tag visible to the user, the system automatically replaces it without creating a new notification.
Your can use this to group messages that are contextually relevant into one notification. This is a good practice if your site creates many notifications that would otherwise become overwhelming to the user.
When to show notifications
Depending on the use case, if the user is already using our application we may want to update the UI instead of sending them a notification.
In the push
event handler in sw.js
, replace the event.waitUntil()
call with the following code:
event.waitUntil(
clients.matchAll().then(c => {
console.log(c);
if (c.length === 0) {
// Show notification
self.registration.showNotification('Push Notification', options);
} else {
// Send a message to the page to update the UI
console.log('Application is already open!');
}
})
);
Save the file and update the service worker, then refresh the page in the browser. Click Enable Push Messaging. Copy the subscription object and replace the old subscription object in node/main.js
with it.
Execute the command to run the node server in the command window at the app/
directory:
node node/main.js
Send the message once with the app open, and once without. With the app open, the notification should not appear, and instead a message should display in the console. With the application closed, a notification should display normally.
Explanation
The clients
global object in the service worker lists all of the active clients of the service worker on this machine. If there are no clients active, we create a notification.
If there are active clients it means that the user has your site open in one or more windows. The best practice is usually to relay the message to each of those windows.
Hide notifications on page focus
If there are several open notifications originating from our app, we can close them all when the user clicks on one.
In sw.js
, replace the TODO 5.3 in the notificationclick
event handler with the following code:
self.registration.getNotifications().then(notifications => {
notifications.forEach(notification => {
notification.close();
});
});
Save the code.
Comment out the tag
attribute in the displayNotification
function in main.js
so that multiple notifications will display at once:
// tag: 'id1',
Save the code, open the app again, and update the service worker. Enable push messaging, close the app, and click Notify me! a few times to display multiple notifications. If you click "Close the notification" on one notification they should all disappear.
Note: If you don't want to clear out all of the notifications, you can filter based on the tag
attribute by passing the tag into the getNotifications
function. See the getNotifications reference on MDN for more information.
Note: You can also filter out the notifications directly inside the promise returned from getNotifications
. For example there might be some custom data attached to the notification that you would use as your filter criteria.
Explanation
In most cases, you send the user to the same page that has easy access to the other data that is held in the notifications. We can clear out all of the notifications that we have created by iterating over the notifications returned from the getNotifications
method on our service worker registration and then closing each notification.
Solution code
The solution code can be found in the solution/
directory.
Notifications and tabs
We can re-use existing pages rather than opening a new tab when the notification is clicked.
In sw.js
, replace the code inside the else
block in the notificationclick
handler with the following code:
event.waitUntil(
clients.matchAll().then(clis => {
const client = clis.find(c => {
return c.visibilityState === 'visible';
});
if (client !== undefined) {
client.navigate('samples/page' + primaryKey + '.html');
client.focus();
} else {
// there are no visible windows. Open one.
clients.openWindow('samples/page' + primaryKey + '.html');
notification.close();
}
})
);
Save the code and update the service worker in the browser. Enable push messaging and click Notify me! to create a new notification. Try clicking on a notification once with your app open and focused, and once with the app closed.
Note: The clients.openWindow
method can only open a window when called as the result of a notificationclick
event. Therefore, we need to wrap the clients.matchAll()
method in a waitUntil
, so that the event does not complete before openWindow
is called. Otherwise, the browser throws an error.
Explanation
In this code we get all the clients of the service worker and assign the first "visible" client to the client
variable. Then we open the page in this client. If there are no visible clients, we open the page in a new tab.
For more information
Solution code
The solution code can be found in the solution/
directory.
In this lab you have learned how to create notifications and configure them so that they work well and look great on the user's device. You learned how to subscribe a user to push messaging and how to push messages from a Node.js server. Finally, you learned some best practices that will enable you to re-engage with your users more effectively.
What we've covered
- How to create notifications and configure them.
- How to build notifications that the user can interact with through either a single tap, or by clicking on one of a number of different actions.
- How to send messages to the user's device whether or not they have the browser open through the Open Web Push protocol, and how to implement this across all the browsers that support this API.
Resources
Introduction to push notifications
Demos
Learn about Web Push libraries
Learn about encryption
Learn about Firebase Cloud Messaging
To see all the codelabs in the PWA training course, see the Welcome codelab for the course/