Make your Progressive Web App not feel like a website, but like a "real" app
When you play Progressive Web App buzzword bingo, it is a safe bet to set on "PWAs are just websites". Microsoft's PWA documentationagrees,wesay iton this very site, and even PWA nominators Frances Berriman and Alex Russellwrite so,too. Yes, PWAs are just websites, but they are also way more than that. If done right, a PWA will not feel like a website, but like a "real" app. Now what does it mean to feel like a real app?
To answer this question, let me use the ApplePodcastsapp as an example. It is available on macOS on desktop and on iOS (and iPadOS respectively) on mobile. While Podcasts is a media application, the core ideas I illustrate with its help apply to other categories of apps, too.
Capable of running offline
If you take a step back and think of the platform-specific applications you have on your mobile phone or desktop computer, one thing clearly stands out: you never get nothing. In the Podcasts app, even if I am offline, there is always something. When there is no network connection, the app naturally still opens. TheTop Chartssection does not show any content, but instead falls back to aCan't connect right nowmessage paired with aRetrybutton. It may not be the most welcoming experience, but I get something.
The Podcasts app follows the so-called app shell model. All the static content that is needed to show the core app is cached locally, including decorative images like the left-hand menu icons and the core player UI icons. Dynamic content like theTop Chartsdata is only loaded on demand, with locally cached fallback content available should the loading fail. Read the articleThe App Shell Model to learn how to apply this architectural model to your web app.
Offline content available and media playable
While offline, via the left-hand drawer, I can still navigate to theDownloadedsection and enjoy downloaded podcast episodes that are ready to be played and are displayed with all metadata like artwork and descriptions.
Previously downloaded media content can be served from the cache, for example using the Serve cached audio and video recipe from theWorkboxlibrary. Other content can always be stored in the cache, or in IndexedDB. Read the articleStorage for the web for all details and to know when to use what storage technology. If you have data that should be persistently stored without the risk of being purged when the available amount of memory gets low, you can use the Persistent Storage API.
Proactive background downloading
When I am back online, I can of course search for content with a query likehttp 203
,and when I decide to subscribe to the search result, theHTTP 203 podcast,the latest episode of the series is immediately downloaded, no questions asked.
Downloading a podcast episode is an operation that potentially can take longer. TheBackground Fetch APIlets you delegate downloads to the browser, which takes care of them in the background. On Android, the browser in turn can even delegate these downloads further on to the operating system, so the browser does not need to be continuously running. Once the download has completed, your app's service worker gets woken up and you can decide what to do with the response.
Sharing to and interacting with other applications
The Podcasts app integrates naturally with other applications. For example, when I right-click an episode that I like, I can share it to other apps on my device, like the Messages app. It also naturally integrates with the system clipboard. I can right-click any episode and copy a link to it.
TheWeb Share APIand theWeb Share Target API allow your app to share and receive texts, files, and links to and from other applications on the device. Although it is not yet possible for a web app to add menu items to the operating system's built-in right-click menu, there are lots of other ways to link to and from other apps on the device. With theAsync Clipboard API,you can programmatically read and write text and image data (PNG images) to the system clipboard. On Android, you can use theContact Picker APIto select entries from the device's contacts manager. If you offer both a platform-specific app and a PWA, you can use theGet Installed Related Apps API to check if the platform-specific app is installed, in which case you do not need to encourage the user to install the PWA or accept web push notifications.
Background app refreshing
In the Podcasts app's settings, I can configure the app to download new episodes automatically. Like that, I do not even have to think about it, updated content will always just be there. Magic.
ThePeriodic Background Sync API allows your app to refresh its content regularly in the background without the need for it to be running. This means new content is proactively available, so your users can start delving into it right away whenever they decide.
State synchronized over the cloud
At the same time, my subscriptions are synchronized across all devices I own. In a seamless world, I do not have to worry about manually keeping my podcast subscriptions in sync. Likewise, I do not have to be afraid that my mobile device's memory will be consumed by episodes I have already listened to on my desktop. The play state is kept in sync, and listened-to episodes are automatically deleted.
Syncing app state data is a task that you can delegate to theBackground Sync API.The sync operation itself does not have to happen immediately, justeventually,and maybe even when the user has closed the app again already.
Hardware media key controls
When I am busy with another application, say, reading a news page in the Chrome browser, I can still control the Podcasts app with the media keys on my laptop. There is no need to switch to the app just to skip forward or backward.
Media keys are supported by theMedia Session API. Like that, users can make use of the hardware media keys on their physical keyboards, headphones, or even control the web app from the software media keys on their smartwatches. An additional idea to smooth seeking operations is to send a vibration pattern when the user seeks over a significant part of the content, for example, passing the opening credits or a chapter boundary.
Multitasking and app shortcut
Of course I can always multitask back to the Podcasts app from anywhere. The app has a clearly distinguishable icon that I can also put on my desktop or application dock so Podcasts can be launched immediately when I feel like it.
Progressive Web Apps on both desktop and mobile can be installed to the home screen, start menu, or application dock. Installation can happen based on a proactive prompt, or fully controlled by the app developer. The articleWhat does it take to be installable?covers everything you need to know. When multitasking, PWAs appear independent from the browser.
Quick actions in context menu
The most common app actions,Searchfor new content andCheck for New Episodes,are available right from the context menu of the app in the Dock. Via theOptionsmenu, I can also decide to open the app at login time.
By specifyingapp icon shortcuts in the PWA's web app manifest, you can register quick routes to common tasks that users can reach directly from the app icon. On operating systems like macOS, users can also right-click the app icon and set the app to launch at login time. There is ongoing work on a proposal forrun on login.
Act as default app
Other iOS applications and even websites or emails can integrate with the Podcasts app by leveraging thepodcasts://
URL scheme. If I follow a link likepodcasts://podcasts.apple.com/podcast/the-css-podcast/id1042283903
while in the browser, I am brought right into the Podcasts app and can decide to subscribe or listen to the podcast.
Handling fully custom URL schemes is not yet possible, but there is ongoing work on a proposal for
URL Protocol Handling
for PWAs. Currently,registerProtocolHandler()
with aweb+
scheme prefix is the best alternative.
Local file system integration
You may not immediately think of it, but the Podcasts app naturally integrates with the local file system. When I download a podcast episode, on my laptop it is stored in~/Library/Group Containers/243LU875E5.groups.com.apple.podcasts/Library/Cache
.Unlike, say~/Documents
,this directory is of course not meant to be accessed directly by regular users, but it is there.
Other storage mechanisms than files are referenced in theoffline contentsection.
TheFile System Access APIenables developers to get access to the local file system of the device. You can use it directly or via thebrowser-fs-access support library that transparently provides a fallback for browsers that do not support the API. For security reasons, system directories are not web-accessible.
Platform look and feel
There is a more subtle thing that is self-evident for an iOS application like Podcasts: none of the text labels are selectable and all text blends in with the system font of the machine. Also my choice of system color theme (dark mode) is respected.
By leveraging theuser-select
CSS property with the value ofnone
,
you can protect UI elements from being accidentally selected.
Be sure, though, to not abuse this property for makingapp contentsunselectable.
It should only be used for UI elements like button texts, etc.
Thesystem-ui
value for thefont-family
CSS property allows you to
specify the default UI font of the system to be used for your app.
Finally, your app can obey to the user's color scheme preference by respecting theirprefers-color-scheme
choice, with an optionaldark mode toggle
to override it.
Another thing to decide on might be what the browser should do when reaching
the boundary of a scrolling area, for example, to implement custompull to refresh.
This is possible with theoverscroll-behavior
CSS property.
Customized title bar
When you look at the Podcasts app window, you notice that it does not have a classic integrated title bar and toolbar, like, for example, the Safari browser window, but a customized experience that looks like a sidebar docked to the main player window.
While not currently possible,title bar customizationis being worked on at the moment.
You can (and should), however, specify thedisplay
and the
theme-color
properties of the web app manifest to
determine the look and feel of your application window and to decide which default browser controls—potentially none of them—should be shown.
Snappy animations
In-app animations are snappy and smooth in Podcasts. For example, when I open theEpisode Notesdrawer on the right, it elegantly slides in. When I remove one episode from my downloads, the remaining episodes float up and consume the screen real estate that was freed by the deleted episode.
Performant animations on the web are certainly possible if you take into account a number of best practices outlined in the articleAnimations and Performance. Scroll animations as commonly seen in paginated content or media carousels can be massively improved by using theCSS Scroll Snapfeature. For full control, you can use theWeb Animations API.
Content surfaced outside of app
The Podcasts app on iOS can surface content in other locations than the actual application, for example, in the system's Widgets view, or in the form of a Siri Suggestion. Having proactive, usage-based calls-to-action that just require a tap to interact with can greatly increase the re-engagement rate of an app like Podcasts.
TheContent Index APIallows your application to tell the browser which content of the PWA is available offline. This allows the browser to surface this content outside of the main app. By marking up interesting content in your app as suitable forspeakable audio playback and by usingstructured markupin general, you can help search engines and virtual assistants like the Google Assistant present your offerings in an ideal light.
Lock screen media control widget
When a podcast episode is playing, the Podcasts app shows a beautiful control widget on the lock screen that features metadata like the episode artwork, the episode title, and the podcast name.
TheMedia Session APIlets you specify metadata like artwork, track titles, etc. that then gets displayed on the lock screen, smartwatches, or other media widgets in the browser.
Push notifications
Push notifications have become a bit of an annoyance on the web (albeitnotification prompts are a lot quieternow). But if used properly, they can add a lot of value. For example, the iOS Podcasts app can optionally notify me of new episodes of podcasts I am subscribed to or recommend new ones, as well as alert me of new app features.
ThePush API allows your app to receive push notifications so you can notify your users about noteworthy events around your PWA. For notifications that should fire at a known time in the future and that do not require a network connection, you can use theNotification Triggers API.
App icon badging
Whenever there are new episodes available for one of the podcasts I am subscribed to, an app icon badge on the Podcasts home screen icon appears, again encouraging me to re-engage with the app in a way that is not intrusive.
You can set app icon badges with theBadging API. This is especially useful when your PWA has some notion of "unread" items or when you need a means to unobtrusively draw the user's attention back to the app.
Media playback takes precedence over energy saver settings
When podcast media is playing, the screen may turn off, but the system will not enter standby mode. Apps can optionally keep the screen awake, too, for example to display lyrics or captions.
TheScreen Wake Lock APIallows you to prevent the screen from turning off. Media playback on the web automatically prevents the system from entering standby mode.
App discovery through an app store
While the Podcasts app is part of the macOS desktop experience, on iOS it needs to be installed from the App Store.
A quick search forpodcast
,podcasts
,orapple podcasts
immediately turns the app up in the App Store.
While Apple does not allow PWAs on the App Store, on Android, you can submit your PWA
wrapped in a Trusted Web Activity.
Thebubblewrap
script makes this a painless operation.
This script is also what internally powersPWABuilder's Android app export feature,
which you can use without touching the command line.
Feature summary
The table below shows a compact overview of all features and provides a list of useful resources for realizing them on the web.
Conclusion
PWAs have come a long way since their introduction in 2015. In the context ofProject Fugu 🐡,the cross-company Chromium team is working on closing the last remaining gaps. By following even only some of the pieces of advice in this article, you can piece by piece get closer to that app-like feeling and make your users forget that they are dealing with "just a website", because, honestly, most of them do not care how your app is built (and why should they?), as long as it feels like arealapp.
Acknowledgements
This article was reviewed by Kayce Basques, Joe Medley, Joshua Bell, Dion Almaer, Ade Oshineye, Pete LePage, Sam Thorogood, Reilly Grant, andJeffrey Yasskin.