 Push notifications makes use of two APIs. The notification API to display notifications and the push API to handle messages that have pushed your client from your server via the push service used by the browser. This diagram gives an overview. On the client side, your web page interacts with service workers, which in turn receive push events via the user agent, also known as the browser. And on the back end, you send messages from your application server to the push service, which then delivers them to the correct client. Let's look at the notification API first. This allows developers to display notifications to the user. Before we can create a notification, we need to get permission from the user. This code will prompt the user permissions to show notifications. You can try this out from the browser console. As you'll see later, permission is requested automatically when subscribing to a push service. So there's no need to call this function when using just push notifications. Let's take a look at some examples for configuring and displaying a notification from a service worker. We first check that permission has been granted. Then we call show notification on the service worker registration object and pass in the notification title. You can also try this out from the browser console. Try it on the new tab page. Now, for push notifications, you call show notification in the service worker in response to a push event when a message arrives. We can specify an optional options object to configure the notification. This is passed in as the second argument in the show notification function. The body property is the body text displayed below the title. Icon is the image displayed at the top of the notification. Vibrate is the vibration pattern for phones. In this case, 100 milliseconds on, 50 milliseconds off, 100 milliseconds on, it's on. Data is the arbitrary data we can retrieve in the service worker when the user interacts with the notification. In this example, primary key allows us to identify which notification was clicked when handling the interaction in the service worker. Let's try that out. We can add action buttons to the notification that we can then handle each in a different way. Here's what that looks like. Notification interaction events are handled in the service worker, tapping, clicking, or closing the notification. There are two notification interactions you can listen for in the service worker. Notification close. The notification close event only triggers when the notification is dismissed via a direct action on the notification. If the user dismisses all notifications, the event will not trigger. And this is done to save resources. Notification click. If the user clicks the notification or an action button in the notification, the notification click event is triggered. If the user clicked on an action, the action is attached to the event object of the notification click handler. We can check which action was triggered and handle it separately. Now let's see how the two handlers work in a service worker. First, notification close. We access the notification object from the event object and we can get the data from the notification object. We might use the primary key property from the data to identify which notification was clicked. In a notification click handler, we can determine what action button the user pressed by inspecting the action property on the event object. Note that each browser displays notification actions differently and some don't display them at all. To compensate, we put a default experience in this example in an else block after checking which action was clicked so that something will happen on a simple click of the notification. Now let's see how you send push messages from your server and handle incoming messages on your client web app. Each browser manages push notifications through its own system called a push service. When a user grants permission for push on your site, you subscribe them to the browser's push service. This creates a subscription object that includes a public key to enable messages to be encrypted and an endpoint URL for the browser's push service, which is unique for each user. From your server, send your push messages to this URL encrypted with the public key. The push service sends the message to the right client. Now the service worker will be woken up to handle incoming push messages when a push event is fired and this allows your app to react to push messages, for example, by displaying a notification using service worker registration show notification. Your app doesn't need to listen to or poll for messages and the browser doesn't even need to be open. All the work is done under the hood as efficiently as possible by the browser and the operating system. And this is great for saving battery and CPU usage. Let's go through that step by step. In the app's main JavaScript, call pushmanager.subscribe on the service worker registration object. Get the subscription object and convert it to JSON. Get the endpoint URL and public key and save this to your server, for example, by using a fetch request. Send the message payload from your server to the endpoint URL encrypted with the public key. The push message raises a push event in the service worker, which we can handle in a push event handler. In push event handler, we get the data from the message and display a notification. The push API allows users to subscribe to messages sent from your app server that are sent via the push service used by the browser. And subscribing, of course, is done in the JavaScript for the page. Responding to push events, for example, by displaying a notification is done in the service worker. Just to repeat, subscribing to the push service and getting the subscription object happen in the JavaScript for the page. First, we check if the user is already subscribed and update the page UI accordingly. If they are not subscribed, prompt them to subscribe. If they are already subscribed, update the server with the latest subscription, since that may have changed by the push service since it was last used. When the user grants permission for push on your site, you subscribe them to the browser's push service. As I said before, this creates a special subscription object that contains the endpoint URL for the push service, which is different for each browser, along with a public key. We send the subscription object for this user to the server and save it. Now, before you subscribe a user, check if you already have a subscription object. If you don't have the object, again, update the UI to prompt the user to enable push notifications. And if you do have the subscription object, update your server database with the latest subscription object. The ready property of the service worker defines whether a service worker is ready to control a page or not. It returns a promise which resolves to a service worker registration object when the service worker becomes active. The get subscription function returns the subscription object or undefined if it doesn't exist. We need to perform this check every time the user accesses our app because it is possible for subscription objects to change during their lifetime. This is the process of subscribing to the push service. Register the service worker from the main page, main JS. This request goes to the user agent. The user agent returns the service worker registration object. Use the service worker registration object to access the push manager API. And from that request is subscribed to the push service. This request is passed on to the push service. The push service returns the subscription object which includes the endpoint URL and the public key. Save the subscription object data to your server and send push messages from your server to the endpoint URL encrypted with the public key, like I said. Now, before sending notifications, we must subscribe to a push service. We call push manager subscribe on the service worker registration object to subscribe. And the resulting push subscription object includes all the information that the application needs to send a push message, an endpoint, and the encryption key needed for sending data. Each subscription is unique to a service worker. The endpoint for the subscription is a unique capability URL. Knowledge of the endpoint is all that is necessary to send a message to your application. The endpoint URL therefore needs to be kept secret or other applications might be able to send push messages to your application. Here's an example of the subscription object. This is the object returned from the push service when we call reg.pushmanager.subscribe. The subscription object has two parts. The first part is an endpoint URL, the address on the push service to send messages to. This includes an ID that enables the push service to send a message to the correct client and service worker. The second part of the subscription object is the keys property. The P256DH key is an elliptic curve Diffie-Hillman ECDH public key for message encryption. The ORTH key is an authentication secret that your application server uses in authentication of its messages. These keys are used by your application server to encrypt and authenticate messages for the push subscription. And let's see how the process of sending a message is done. The server generates a message, encrypts it with the public key, and then sends it to the endpoint URL in the subscription object. The URL contains the address of the push service along with a subscription ID, which allows the push service to identify the client to receive the message. The message is received in the push service, which routes it to the right client. And the process of sending a push message from the server works like this. A back-end service on your server sends a push message to the push service using the endpoint URL from the subscription object. The message must be encrypted with the public key from the subscription object. The push service uses subscription IDs encoded in the endpoint URL to send the message to the right user agent. The push event is picked up by the service worker. The service worker gets the data from the message and displays a notification. In this example, we're using Google's web push library for Node.js to send a push message from a Node.js server. The TTL value in the options specifies the time in seconds that the push service should keep trying to deliver the message. Now, this is important to set correctly. Some messages have a short life. Some may be valid for several hours or more. We then pass in the subscription object, payload, and options object to send notification. You need a way to ensure secure communication between the user and your server and between your server and the push service and between the push service and the user. In other words, the user needs to be sure that messages are from the domain they claim to be from and have not been tampered with by the push service. You need to make sure the user is who they claim to be. Vapod was created to solve this problem. This vapod identification information can be used by the push service to attribute requests that are made by the same application server to a single entity. This can be used to reduce the secrecy for push subscription URLs by being able to restrict subscriptions to a specific application server. An application server is further able to include additional information so that the operator of a push service can use to contact the operator of the application server. In order to use vapod, we need to generate a public-private key pair and subscribe to the push service using the public key. The public key must be first converted from URL base 64 to a Uint8 array. This is then passed into the application server key parameter in the subscribe method. The web push library provides a method to generate vapod keys which generates the keys. This should be used once in the command line, web push generate vapod keys, dash dash jason, and the keys stored somewhere safe. We can use the web push library to send a message with the required vapod details. We add a vapod details object in the options parameter that includes the parameters required for the request signing. Now, let's look at messages from the receiving end in the web app on the client. Handling push events happens in the service worker. The service worker will be woken up to handle incoming push messages and a push event is fired. This allows your app to react to push messages, for example, by displaying a notification using service worker registration show notification. To display a push notification, you listen for the push event in the service worker. You get the push message data from the push event object. In this example, we simply convert the message data to text. We wrap show notification in a wait until to extend the lifetime of the push event until the show notification promise resolves. The push event will not be reported as successfully completed until the notification has displayed. You can practice working with the notification and the push API by following the lab that accompanies this video. One small gotcha, don't use private or incognito mode for this lab. For security reasons, push notifications are not supported in private or incognito mode.