Building a Baseline Progressive Web App - Part 1

Just like "responsive web design" was a buzzphrase a few years ago, a current buzzphrase is Progressive Web App (PWA).

What is a PWA? According to Wikipedia, a PWA is a web app "that uses the latest web technologies. Progressive web apps are technically regular web pages (or websites) but can appear to the user like traditional applications or (native) mobile applications."

I think of it more of a list of standards that every 2017 web application should adhere to. Some of it is pretty obvious (and many are already doing) even if you have never heard of PWAs (e.g. serving the website over HTTPS and making pages responsive on all devices).

Google have very put together a checklist and a tool (called Lighthouse) that can be used to verify a PWA. It checks against this list as well as a subset of other best practices and gives a full report of what was good and bad.

There are 2 tiers on the checklist: the baseline list, which is the bare minimum to be classified totally as a PWA, and the exemplary list, which are fore PWAs that take things even further.

This post will go through the motions of converting an existing site to a baseline PWA to pass this list. The items are:

  • Site is served over HTTPS
  • Pages are responsive on tablets & mobile devices
  • Each page has a URL
  • Metadata provided for Add to Home screen
  • The start URL (at least) loads while offline
  • First load fast even on 3G
  • Site works cross-browser
  • Page transitions don't feel like they block on the network

A few of these could have entire blog posts on their own and perhaps I will expand on them in the future.

This is Part 1, which will address the first 4 points. Part 2 will address the others next week.

The Website

Some time ago, I built a very simple Unix timestamp convertor. By the time you are reading this, it will be a PWA, however, at the time of writing, it is a very basic PHP based single web page.

I ran the Lighthouse tests against it before I started this project and it scored 37/100.

Screenshot of lighthouse score

As I said before, being a PWA is more of a scale and I don't think very many modern websites will be on the 0 end of the scale. 37% is not great (by my university's standards, 40% was the minimum "pass" mark), but clearly some things are already OK.

Most notable good things are that the website already loads fast (well, there isn't much to load), it uses all the latest JS and CSS features that are compatible on every browser (Bootstrap deals with this for me) and it is mobile responsive (Bootstrap deals with this for me).

Site is served over HTTPS

This is the easiest one to deal with first.

Let's Encrypt is a free certificate authority that allows you to quickly and easily install a SSL Certificate onto your server and automatically renew it when it needs to.

I will use the Certbot client as this is the easiest to set up on Ubuntu and Apache. There is excellent documentation on their website to guide you through the process for whichever OS/Web Server combination that you are using. I am using Ubuntu and Apache, so after SSHing into my server, I do:

sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install python-certbot-apache 

The first line adds their repository to your package manager, and then you are simply installing it.

Once installed, do:

certbot --apache

This will begin the wizard for creating the certificate. It asks which domain you wish to have the certificate for if you have multiple domains on that server and for an e-mail address that they will contact you when it need renewing. That is it. The process is simple.

It will then ask you if you want to support both HTTP and HTTPS requests or have certbot automatically set up the vhosts files to stop redirect HTTP to HTTPS. I am going to do the latter.

Now if you go to the site, you will see that it is secure:

As I said, this is a very brief outline of how to set up the most basic configuration of SSL. For example, sometimes you may not want all of the default settings (and it may not even be able to do it). Perhaps I will do a full post on this in the future.

By the way, just by doing this step, my Lighthouse score has now jumped up to 50%, so I am halfway to becoming a PWA.

Pages are responsive on tablets & mobile devices

As I said earlier, this part is already done since I am using Bootstrap for my templates and this takes care of all the responsive stuff. The Lighthouse test from earlier confirms this.

Each page has a URL

This is another thing that was already implemented. It is basically a single page application but using the converter will generate a URL. That is, the URL determines the value in the text box and that something is converted. This gives the effect that ever page has its own URL. This will have to be maintained going forward.

Metadata provided for Add to Home screen

This step allows users who are using Google Chrome on an Android device to press a button that will add an icon to your website to their home screen. This means it will look as though it is a native app and when it loads, it will act like one (rather than open up in the browser).

I am not 100% convinced by this feature. Firstly the compatibility is very low and secondly because I don't see the point of abstracting it away from the fact that it is on the web. But I guess it is a core idea of a PWA and the offline capabilities are important for this (for example, native apps don't fail to open if there is no connection, worse case scenario, they have a holding page that tells you this).

To do this, you need to make a manifest file with the following information:

  • a short name - 12 chars is the suggested maximum homescreen label length
  • a long name
  • a list of icons with various resolutions - this post was excellent in explaining of this. I also used this tool to generate all of the icon sizes (it also generates a manifest file with all of the icons in it and what needs to go into your HTML) after I created one.
  • a start URL - which could be a special launch page or just the homepage

You can also add:

  • a background colour
  • and whether it is a standalone app or if you would like it to appear in a web browser

Setting the Icons and the Title will be used for the app icon as well as the splash screen whilst the app is loading. Let's have a look at my manifest file (which I saved as manifest.json):

    "short_name": "Unix Time",
    "name": "Convert Unix Time",
    "icons": [
            "src": "\/web\/images\/launchericons\/android-icon-36x36.png",
            "sizes": "36x36",
            "type": "image\/png",
            "density": "0.75"
            "src": "\/web\/images\/launchericons\/android-icon-48x48.png",
            "sizes": "48x48",
            "type": "image\/png",
            "density": "1.0"
            "src": "\/web\/images\/launchericons\/android-icon-72x72.png",
            "sizes": "72x72",
            "type": "image\/png",
            "density": "1.5"
            "src": "\/web\/images\/launchericons\/android-icon-96x96.png",
            "sizes": "96x96",
            "type": "image\/png",
            "density": "2.0"
            "src": "\/web\/images\/launchericons\/android-icon-144x144.png",
            "sizes": "144x144",
            "type": "image\/png",
            "density": "3.0"
            "src": "\/web\/images\/launchericons\/android-icon-192x192.png",
            "sizes": "192x192",
            "type": "image\/png",
            "density": "4.0"
    "theme_color": "#000000",
    "background_color": "#000000",
    "display": "standalone",
    "start_url": "/"

I also added the newly created icons to my HTML:

<link rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png">
<link rel="icon" type="image/png" sizes="192x192"  href="/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">

Then I linked the manifest file:

<link rel="manifest" href="/manifest.json">

Also you can add theme colours to the HTML here as well. This will do cool things like make the Google Chrome App header change colour to match your brand:

<meta name="msapplication-TileColor" content="#000000">
<meta name="msapplication-TileImage" content="/ms-icon-144x144.png">
<meta name="theme-color" content="#000000">

If I open the website on Google Chrome on my phone, I see that the address bar matches the theme of my website:

I also now see the option to "Add to Home screen":

Doing this gives me a chance to rename it, but notice the default is what I called it in the manifest:

There it is on my home screen with my other apps:

When I open it, I get an automatically generated splash screen (as I declared in the manifest:

And then the app opens, full screen as though it is native:


So running this in the Lighthouse tool now gives me a score of 85/100! A vast improvement from before. You don't need this score to see how it is just like using a native app.

However, the illusion is broken if I suddenly lost Internet connection (or it is very slow). That is what the second half of the checklist covers and what I will overcome next week.

© 2012-2023