 Progressive Web Apps give us an opportunity to reset our expectations and loudly declare we can do better when building Web Apps. I'm Pete, a developer advocate on the web team at Google. Building an engaging Progressive Web App goes beyond functional and ensures that the whole experience is delightful, making it easy for the user to do what they need to do. Slapping a service worker on an existing app is easy and it will improve the reliability of the app, but that alone doesn't radically improve the user experience. It falls short of the full benefits of a Progressive Web App. Building an engaging Progressive Web App requires us to shift the way we think about visual and interaction design from the conventional web patterns and instead consider some native patterns. The team at Twitter did a great job of this with Twitter Lite. Compare their website with Twitter Lite and their native app. Things like the footer that typically exist on the web aren't there or have shifted into other places. Links still exist but don't necessarily feel like links and navigating between pages feels more like a transition and less like a navigation. It's important to pay attention to detail here. Native apps have given users expectations around touch interactions and information hierarchy, so it's important to create a consistent experience for users to avoid creating a jarring experience. I could spend a lot of time here but unfortunately we don't have enough time. Instead as you work on your Progressive Web App, check out similar apps on iOS and Android. Browse sites like Dribble for design inspiration. Then spend some time browsing the material design specification and the iOS human interface guidelines to increase your familiarity with common UI components and their interaction. The idea of notifications is not new but it's now a feature available to web apps and a great feature to help build engagement even when the browser isn't open. Web push notifications aren't just a Chrome thing. Microsoft has indicated they plan to support them. Firefox, Opera and Samsung browser already provide support. Carnival Cruise Lines, one of the world's largest leisure travel companies, wanted to enhance how it re-engages with its customers. The objective was to send timely, customized information that did not have to compete with the customer's inbox and worked on all devices and was easy to act on. Working with MobileFi, Carnival implemented push notifications for its mobile web users. Carnival's customers clearly feel these notifications are valuable to them with 24% of users opting in and a click-through rate of 42%. Carnival can now reach customers on multiple types of devices without having to wait for the user to check their email and possibly miss the opportunity to book their vacation before their hold expires. As you plan your notifications, ask yourself, are they important enough to warrant an interruption? If you're unsure, allow the user to opt in to specific types of notifications inside your app with their own notification settings. Users want notifications that have timely information, offer enough information to avoid visiting the app, are personal or contextual, and in short, are day altering. Let's take a look. Use notifications primarily for time-sensitive events, especially if these synchronous events involve other people. For instance, an incoming chat is a real-time and synchronous form of communication. Another user is actively waiting for me to respond. Calendar events are another good example of when to use a notification. The event is imminent and calendar events often involve other people. You want to avoid notifying the user of information that is not directed specifically at them or information that isn't truly time-sensitive. For instance, the asynchronous and undirected updates flowing through a social network generally do not warrant a real-time interruption. Let's look at some of the other things that a notification should be. Notifications aren't emails. The intent of a notification is to tease the user so that they'll open up your app or to let them complete a task without having to open the app. Don't interrupt the user for low-level technical operations like saving or syncing information or updating an application if the app or system can resolve the issue without involving the user. Keep it personal. If it's a chat notification, tell them who it's from. Don't create a notification if the relevant new information is currently on screen. Instead, use the UI of the application itself to notify the user of the new information directly in context. For instance, a chat application shouldn't create a system notification if I've already got the chat window open and I can see it. Let's test our criteria against some of these notifications. This is a great notification and it hits on all three points. My flight's delayed. It's timely. Well, it's helpful now. It's precise. It includes the new flight time and it's relevant. It includes the flight information. Hmm, this one not so good. It's probably timely, but we don't know for sure. It's certainly not precise. It doesn't say which card or why. It's probably relevant, but it's my card, but which card? I've got a couple of cards. So how do we make it better? With a few small changes and the addition of action buttons, it becomes more precise, relevant, and timely. Okay, it's Google Plus. I don't think I need to say anything more. All right, this one's timely, but who's it from and what does it say? With a few adjustments, like adding an image, adjusting the title to include who the message is from, and part of the message in the body, I can much more easily decide what I want to do with it. Now, if Google started its own self-driving car company, I hope they'd call it goober. In any event, this one, it's timely. My car's arrived, it's precise. I need to act on it and get into my car, and it's relevant. It's something I should be interested in. You're going to have plenty of opportunities to monetize your user experience, but don't blow it by spamming users. If you spam your users with notifications, they may stop allowing them altogether. All right, question. It's timely. I know Mary just answered my question. It's precise because it tells me what happened, though it could be better if it gave me the answer, but fitting that whole answer into the notification may be hard, and it's relevant. It tells me who and what happened. There are three key steps to implementing web push and notifications. Adding the client-side logic to subscribe the user, your back end to manage who's subscribed and trigger sending the message, and finally the service worker that will receive the push event and show the notification to the user. On the client, we need to provide an easy way for the user to subscribe or unsubscribe from our notifications, but before they can even subscribe, we need to get their permission. Once we have their permission, we can use the push API to create a subscription and get the push subscription object. You can think of it like an ID for that user's device. It also includes a set of encryption keys that we'll need later to send a payload with our message. Then you'll need to send that push subscription object to your server, and save it so that you can use it later when you're ready to send a message to the user. When you want to send a push message to the user, create the message on our server and use the web push protocol to send the message to the push service, sometimes referred to as an endpoint. The push service is then responsible for validating the message and delivering it to the device. If the device is offline, the message is queued until the device comes back online later. Each browser typically has its own push service, but they all have the same API, known as the web push protocol, and behave in the same way. The web push protocol standardizes the way you send a message to a user and provides instructions on how to send that message. The instructions include details like who the message is for, how long it should attempt to deliver the message, and potentially a payload. If you include a payload, it must be encrypted, so that way it can't be viewed by the push provider. The push service receives the message, validates it, and delivers it to the appropriate browser. The URL for the push service is the endpoint attribute from the push subscription object that we saved earlier. Using a push service allows us to leverage the capabilities of the device and shifts the hard work to the OS. There's no need for us to be resident in memory or maintain a connection to our server, both of which can quickly kill the battery. Only when a message arrives does our app wake up. When the message arrives on the device, the OS delivers it to the browser, which then decrypts the payload, wakes up the service worker, and fires the push event where you can handle any background tasks and show the notification. Before we go too far, we need to create a set of application server keys, sometimes referred to as vapid keys. The application server keys are a public and private key pair that are unique to your application. The public key will be used in the client-side subscription code. The private key is used to sign the outgoing message. This allows the push service to validate the signed message against your public key to ensure that the message came from you and helps to prevent anyone else from sending messages to your users. There are a bunch of different ways that you can create these application server keys. You can create it yourself with something like crypto.create.ecdh or you can use the web push library, which is my recommendation, and it simplifies web push. Or you can also hit web push codelab.appspot.google.com. One reminder, keep your private key private. Don't accidentally check it into GitHub or anything like that. Once you've got a handle on setting up the vapid keys, you need to get the user subscribed. Let's take a look at how we do that. Remember, these are progressive web apps. So first, let's check if the browsers support service workers and push. If it does, we'll show the web push UI. Next, we need to register the service worker and grab the registration. Then use the push manager API on the service worker registration to get the subscription. If we get a subscription object back, the user has already subscribed. When the user clicks on the subscribe button, we grab our service worker registration and call pushmanager.subscribe with a set of options. Those options must include user visible only true, which is a symbolic promise between you and the browser that anytime you send a push, you will show a notification. And you need to include your public application server key that you created earlier. If the user hasn't already granted permission to show notification, the browser will request this permission for you. With permission granted, we get the subscription object back. Next, we need to update our UI and send the subscription object to our server so that we can use it later. The push subscription object contains all of the required information needed to send a push message. The endpoint is the push services URL, and the keys object contains the keys needed to encrypt the payload. Typically, the easiest way to send it to your server is to json.stringify it, then use an XHR to send it up to your server. When and how you prompt the user and ask permission to send and show notifications is really important. If the user sees the permission prompt without any context, they're almost guaranteed to click block. And if that happens, your web app will be unable to ask the user for permission again. They'll have to manually unblock your app by changing its permission state, which is buried in the settings panel. Think carefully about how and when you ask users for permission, because if they click block, there is no easy way to reverse that decision. The good news is that most users are happy to give their permission as long as they know why the permission is being asked. In some cases, asking for permission early is important. For example, instant messaging apps or an email client. For that case, consider the double permission pattern. First, show a fake permission prompt that your website controls, consisting of buttons to allow or ignore the permission request. If the user clicks allow, trigger the permission request, prompting the user with the real browser permission dialogue. With this approach, you can display a custom permission prompt in your web app, which asks the user to enable notifications. By doing this, the user can choose to enable or disable notifications without the risk of you being permanently blocked. Weather.com has added push notifications to the settings panel in their web app. Let's take a quick look at their flow. Subscribing and unsubscribing is easy. They've tied the user's goals, staying up to date with the latest weather information, getting safety alerts, and so forth, with the reason why they want to send notifications. When the user subscribes and the subscribe method is called, the browser checks to see if the user has granted permission to send notifications. If the user hasn't granted permission before, it then prompts the user. By engaging with the user first and giving them that chance to opt in, you've essentially guaranteed that they'll click allow and everything will be peachy. But if you don't do it in context and the user doesn't understand what kind of notifications you're going to send or what the benefit to them is, they're more than likely going to hit block. And again, if that happens, the only way to undo the block is for the user to go in and change their browser settings. You really want to avoid surprising the user by asking permission without explaining what the notifications are for. One of the other things I really like about the Weather.com experience is that they give me options about what types of notifications I want. You might only want severe weather alerts or breaking news. Let's check out the way to unsubscribe a user. Unsubscribing is essentially the same. Grab the service worker registration, then get the subscription, and call unsubscribe on it, and then update any UI. In theory, using the web push protocol is easy. It's not. Create your message, encrypt it using the user's public key and your private encryption key. Then use the vapid keys to sign it with your private application security key. Next, set the right set of HTTP headers and make a HTTP post request to send it to the endpoint, which will then deliver it to the device. Ugg. The pain. Instead, I'd highly recommend checking out one of the web push libraries. The one I'll focus on is Node-based, but there are ones for other languages available. With the web push library, sending a message is as simple as calling the API. First, we need to define the options, which include the application server key and some contact info about my application. The subject is sent to the web push service as part of the request to trigger the push and is used if the push service needs to get a hold of me. I've also set a TTL of 120. The TTL property tells the push service how long it should try and reach the device to send the message. A TTL of 120 means that it will try to reach the device for 120 seconds. If the phone is off or in airplane mode during that time and the message isn't delivered, the endpoint will just throw the message away. By default, the TTL is four weeks. The web push library handles the payload encryption for me, so I simply need to convert the payload from a JSON object to a string. And I'm ready to send the message. Send notification, the subscriber, the payload, and the options. That's it. If it works, we'll get a 201 okayback and if it fails, we'll need to handle that in a catch block. Okay, so now what do we do on the client to handle the message? This is a pretty simple push event handler. If the push includes a payload, we get the JSON. Otherwise, it uses a predefined title and calls show notification. In addition to adding a body, you can also add other properties to the notification. Body is exactly as it sounds and can define the text below the title. The icon is a small image shown next to the title and body text. You can add an image which is particularly useful for providing an image preview to the user. And for Chrome on Android, you can specify a badge, a small monochrome icon used in the notification bar to portray a little bit more information to the user about where the notification is from. Beyond that, there are several other additional properties that may be helpful. Vibrate allows you to define a vibration pattern that will run when the notification is displayed. Tag allows you to group notifications together. If a notification with that same tag already exists, the new notification will replace the previous one. Renotify works alongside tag. Without Renotify, the replaced notification will not vibrate or play any sound when it's updated. When a user clicks on a notification, by default, nothing happens. It doesn't even close or remove the notification. To handle user clicks, we need to add a notification click event handler to the service worker. In this case, we simply close the notification. But we probably want to do a little bit more than that. Actions allow you to provide another level of interactions to your users by providing additional buttons that the user can click. With Actions, you can make it super easy for a user to complete a task without having to open your app. For example, a user could reshare or like a post, reconfirm a dinner reservation, or place an order. The choice is yours. To add Actions to the notification, we need to add a new Actions property and notification options, and include an action that will identify the action in our event handler, the title, and an optional icon. Now, if the user clicks on the notification or one of the action buttons, we still handle it with notification click event handler, but the button pressed is defined in event.action. If they clicked on the download action button, event.action will be download, or whatever we set it to in our options. Otherwise, event.action will be undefined and will simply open a page to example.com. I've shown you how you can fetch a document or open a window, but there are a number of other patterns that you should consider when implementing notifications. You can collect analytics about how users interact with your notification by handling the notification close event. You can pass information from the push message to the notification click event by adding a data property to the notification options. And I've shown you how you can open a new window, but you can also focus on existing windows. You can merge notifications. For example, instead of showing all the messages in a chat, you can say something like, there are seven unread chat messages. If the user already has your app open, one approach is to send the message from the service worker to your page. This way, the page can show the notification or update the user about the event. Or you can improve the overall user experience of your web app by caching web pages you expect users to visit after clicking on the notification. Of course, these are just a few ideas. Just remember, the key goal is to radically improve the user experience of your app and push notifications are just one tool that you can use. Check the description for links to the slides from this video and some of the links that I shared. Up next, we'll dive into how to implement HTTPS and the key concepts behind building secure experiences.