From now on, I won’t be building any more native apps. All my apps going forward will be progressive web apps. Progressive web apps are web applications which are designed to work even more seamlessly on mobile devices than native mobile apps.

What do I mean by “more seamlessly?” I mean that most web traffic comes from mobile devices, and that users install between 0–3 new apps per month, on average. That means that people aren’t spending a lot of time looking for new apps to try out in the app store, but they are spending lots of time on the web, where they might discover and use your app.

Progressive web applications start out just like any other web app, but when a user returns to the app and demonstrates through usage that they’re interested in using the app more regularly, browsers will invite the user to install the app to their home screens. PWA’s can also benefit from push notifications, like native apps.

This is where it gets interesting. Just like any native app, the progressive web app will have its own home screen icon, and when you click on it, the app will launch without the browser chrome. That means no URL bar and no web navigation UI. Just the phone’s usual status bar and your app in all its almost-full-screen glory.

This has been a long time coming. None of the technology is particularly new — with the notable exception of the emerging cross-platform standard.

Some History

In the early days of the iPhone, there was no app store. Steve Jobs wanted developers to build iPhone apps using standard web technologies.

Sometimes visionaries are spot on, but they’re 10 years ahead of their time. Looking back from 2 years ago, Steve Jobs’ recommendation to build web apps for iPhone was called his “biggest mistake” by Forbes, because native apps became a smashing success.

Looking back today, it seems obvious that he was really onto something — just way ahead of the capabilities of the existing web standards of the day.

A decade later, mobile web standards now support many of the features developers looked for with native apps, and Steve Jobs’ original vision for mobile web applications is now being pursued seriously by the rest of the world. Apple has supported “apple-mobile-web-capable” web apps that you can add to your home screen almost since the beginning using meta tags that help iOS devices find things like suitable icons.

Other vendors followed suit, each creating their own collection of meta tags to declare mobile web app capabilities, but recently, a cross-platform specification was introduced, and now, cross-platform mobile web apps are finally becoming a real thing.

The apps implementing the standard are called progressive web applications, not to be confused with confusingly similar terms like progressive enhancement or responsive apps.

What Are Progressive Web Apps?

Progressive web apps are just web applications designed to be mobile friendly. If the browser sees that the user wants to keep using the app, it may prompt the user to install it to their home screen, dock, etc… In order to qualify though, they have to meet a specific criteria:

Must be HTTPS (see let’s encrypt)

Valid manifest with required properties (Web Manifest Validator)

Must have service worker

Manifest start_url must always load, even offline (using service worker)

must always load, even offline (using service worker) Must supply its own navigation

Should be responsive to different screen sizes and orientations

Of course, using HTTPS and a service worker for offline users is just good practice for any modern app.

What many app builders seem to forget is that if you build a progressive web application, you must be able to navigate the application without the browser chrome and browser navigation gestures. The mobile devices assume that you’ve built your own navigation into the app.

For example, if you have an about page, that page must have a link back to the app UI, or the users will have to close and reopen the app to get back to your main app UI.

Progressive Web Apps How-To

There’s a lot of information about building progressive web applications spread all over the web, but many of them are out of date, and lots of them contain only a fraction of what you need to know to build one. Let’s fix that.

Enable HTTPS

[EDIT: 2020 Update]: Use Next.js and deploy with Vercel, and HTTPS, along with page bundle splitting, static server renders, CDN delivery, cache header management and GitHub CI/CD deployment integration will automatically be handled out of the box. It’s like having the best full-time DevOps team in the world, but instead of costing hundreds of thousands of dollars per year, they save you thousands of dollars per month on hosting bills.

Here’s the old instructions, just so we can laugh at all the hoops we once had to jump through to build an app:

To enable HTTPS, you’re going to need: * A web server (I recommend DigitalOcean) * An SSL certificate * A strong Diffie-Hellman group ( sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048 ) * TLS/SSL config for your web server (instructions for Nginx on Ubuntu)

The Manifest

The manifest file is called manifest.json and it’s pretty simple. It consists of the name ( short_name for the home screen icon, and an optional name for a more complete name), a start url, and a large list of icons so you can support the large range of different icon sizes needed for various platforms. For Android + iOS, you’ll need:

36x36

48x48

60x60 (Apple touch icon iPhone)

72x72

76x76 (Apple touch icon iPad)

96x96

120x120 (Apple touch icon iPhone retina)

152x152 (Apple touch icon iPad retina)

180x180 (Apple touch icon for iOS 8+)

192x192

512x512

I singled out the Apple touch icons because they have the well-known names:

apple-touch-icon-180x180.png

Where 180x180 can be replaced by whatever the specific resolution is. Using the well-known names is not required, but if you forget to include the tags, iOS can still find the icons by searching for them in your web app’s root directory if you use the well-known names.

The iOS icons don’t support transparency.

Sample manifest.json:

There are some features you should know about. The theme_color sets the color of the status bar and the window header bar used when switching between apps on Android.

The background_color sets the color used on the splash screen. On Android, a splash screen will be composed from the name property (the long name), and a large icon on top of the background_color .

Manifest isn’t Everywhere

The first time I built a progressive web application, I was thrilled that it worked as expected on Chrome for Android, but when I looked at it in Safari/iOS, it didn’t seem to work. The reason is that mobile Safari, in spite of supporting these features using custom tags for a decade or so doesn’t yet support the web manifest spec.

So, in addition to the manifest file for supported browsers, you’ll also need special meta tags for iOS, beginning with this one, which will launch the app without the browser chrome:

<meta name="apple-mobile-web-app-capable" content="yes">

There are lots of tags to remember, though, and there may be another way to do it. There’s a web manifest polyfill that will read your manifest.json file and add the vendor-specific tags for older mobile browsers, iOS, and even Windows phone and Firefox OS.

Service Worker

Service Worker is a recent web platform specification that allows you to cache resources locally in order to make sure that your app still works, even if the user is not connected to the internet.

It works by hijacking your network requests and serving responses from a local cache when the user is offline. There’s a lot more to it than that, though. It’s a fairly sophisticated low-level API, which allows you to do a lot to optimize your user’s experience whether they’re online or offline.

To get started, I’m going to recommend a very simple higher-level abstraction. A little script called UpUp. Using UpUp is really simple. Here’s an example from the UpUp docs:

The content-url is the URL to load when the user is offline. I just use the app’s root URL for this, and it works fine.

The assets are files that need to be cached locally in order for the app to function properly. Remember to make sure that all your images, icons, CSS, and even default AJAX request responses are included. As you can see, any file type should work.

Eventually, you may want more control over your offline resource caching than UpUp provides. When that day comes, here are some great educational resources to get you started:

Testing

Debugging the physical device with Chrome inspect

Plug your device into a USB cable. Turn on USB debugging on your Android device. See remote debugging instructions. You may need to Google around to figure out how to put your Android phone in developer mode to enable remote debugging.

Once you turn on developer mode, you may see developer options show up in your settings mode. Open that and make sure that USB debugging is turned on.

Visit chrome://inspect#devices . Hit the inspect button and you’ll get the full dev tools for your app.

Verify your service worker

Visit chrome://inspect/#service-workers to verify that your service worker is working properly.

Verify install to homepage

If you want to skip the user engagement checks and always get the install to homepage option, turn on “Bypass user engagement checks” in Chrome flags:

chrome://flags/

To test on desktop, you should also flip “Enable add to shelf”.

Native Apps are Not Dead Yet

Progressive Web Apps now have most of the capabilities of native apps, the install friction promises to be lower than native apps, you’ll no longer need to worry about the app store gatekeepers, and you won’t have to pay anybody 30% tax on app sales for the privilege of being in an app store.

But native apps still have a few capabilities that mobile web apps will not have for a potentially long time.

Notably, most of the sensor and hardware integration specs have limited or no support in most browsers, and even basic features like the device orientation API have undergone breaking changes, with multiple versions of the spec live in various browsers, requiring some tricky logic or polyfills to use safely.

[EDIT: 2020] Apple now supports service worker and web manifest, and even Apple is building PWAs, but they just call them installable web applications.

Conclusion

In the short term, you may still want to produce a hybrid app that can take advantage of some device APIs that are still not available using web standards.

After building my first progressive web application, I’m hopeful for the future, but I’m also conscious that it isn’t perfect. Getting everything to work smoothly across all the device platforms does take a while. You also have to remember that you’ll miss out on the discoverability features and well-known installation procedures that users are familiar with in the app stores.

Hopefully browser vendors will catch up with the vision, and eventually there will be a much better install experience for progressive web applications than there is for native apps. It looks like things are going that way.

Certainly, native apps will survive for a while longer, but if you’re busy learning Swift or Java so you can build native apps, you may want to consider learning JavaScript, instead.

[Update 2020] Want to give some progressive web apps a try? All of these have PWAs now:

Instagram

Twitter

Uber

Spotify

Starbucks

Pinterest

~80k other apps

Edit: The Web Platform Rocks

If you’re about to jump into the comments to tell me how it’s impossible to build a serious app with the web platform:

This is 2016, not 2004. The web platform has come a long way. Read “10 Must See Web Apps and Games” to see what other people have been building for the web platform.

Still not convinced? Read “Why Native Apps Really are Doomed: Native Apps are Doomed pt 2”.

[2020] This article has been edited to reflect the fact that Apple has implemented service workers and standard web manifest files.

[2020] This article has been updated to reflect the fact that many of the world’s most popular applications have PWAs today. That was faster than I expected!