Interpreting and Raising your Lighthouse scores

Published on 9/18/2019

Load time is incredibly important if you want your website or product to remain competitive.

If your load time is slow, users will easily close the window, and you will lose business, period.

I recently started really digging into improving loading times, and started using Chrome's Lighthouse tool to run audits.

Lighthouse is a tool that runs an audit against a site, and will tell you how to improve load times. Some things it may suggest that are easy wins are:

  • Lazy loading images
  • Serving images in next gen formats
  • Minimizing CSS and JS (most frontend frameworks do this by default now)
  • Compressing static assets

I want to focus on some of these Lighthouse tips, and how to implement these changes.

Simulated vs Applied

One thing you will notice when running a Lighthouse audit is that you can use Simulated speeds or Applied speeds.

How do you know which ones are better?

From the Lighthouse Github repo:

Simulated throttling, which Lighthouse uses by default, uses a simulation of a page load, based on the data observed in the initial unthrottled load. This approach makes it both very fast and deterministic. However, due to the imperfect nature of predicting alternate execution paths, there is inherent inaccuracy that is summarized in this doc: Lighthouse Metric Variability and Accuracy. The TLDR: while it's roughly as accurate or better than DevTools throttling for most sites, it suffers from edge cases and a deep investigation to performance should use Packet-level throttling tools.

Request-level throttling , also referred to as Applied throttling in the Audits panel or devtools throttling in Lighthouse configuration, is how throttling is implemented with Chrome DevTools. In real mobile connectivity, latency affects things at the packet level rather than the request level. As a result, this throttling isn't highly accurate. It also has a few more downsides that are summarized in Network Throttling & Chrome - status. The TLDR: while it's a decent approximation, it's not a sufficient model of a slow connection. The multipliers used in Lighthouse attempt to correct for the differences.

So Simulated is still, well, a simulation that suffers from edge cases, and Applied is an approximation, but "not a sufficient model of a slow connection."

You will see that your scores can vary widely between Simulated and Applied. I tend to use Simulated as the benchmark, since that is Lighthouse's default.

Creating a benchmark

One thing I found helpful here is to create a competitive analysis.

I ran Lighthouse audits for competitor websites and plotted them in a graph.

Based on that graph, I plotted how we stacked up against competitor scores.

I then used this data to get buy-in from product on spending more time improving our frontend performance (since that can be a thing hard to explain and get buy-in from non-technical stakeholders).

So what are some of the things we can improve?

Serving next gen formats

One of the things Lighthouse will suggest is to serve images in "next gen formats". But what are next gen formats?

According to Google, WebP, JPEG 2000, and JPEG XR are next gen formats.

But guess what, JPEG 2000 and JPEG XR are both deprecated (so not sure why it's even suggested, TBH!).

What is left is WebP. How do you serve images in WebP then?

Your approach may vary, but I lucked out by the fact I was using Contentful as a CMS (and CDN).

Contentful has an Images API that can serve images in WebP format on the fly. It will also do compression for you.

An advantage of this is that Contentful has built-in caching on their end, so if you request a certain image as a WebP at a certain level of compression, that image will get cached on their end. These requests also do not count against your API limit.

So if you're already using Contentful, you're in luck! If not, and maybe you're using something like Amazon S3, you could write a Lambda that can compress images on the fly. This is an approach I saw a lot when doing research, but can't personally comment on it. You can find more info here though.

Lazy loading images

Lazy loading images simply means you only load images as you need them. So images in a footer may not get loaded on initial load time, but as you scroll down and get closer to the footer, those images will start loading.

This improves your initial load time scores since you're not preloading a lot of images a user may not even end up scrolling down to.

Some approaches will preload a very low-res image prior to loading the full-res image, while other approaches will preload just a background color instead of the actual image, before loading the full-res image.

I pretty much did a search on codepen for lazy loading to get some ideas on implementation.

Ultimately, I used a library for Vue to lazy load. This was an advantage because I was able to very easily combine lazy loading with my image CDN to serve WebP images on the fly and lazy load at the same time!

Applying this to a Vue app: Vue lazyload + Contentful

I used Vue lazy-load as my library, which allows you to listen for certain formats (you can read more here).

Combining my CDN which can serve compressed WebP by requesting the image with certain query parameters, I simply had to add a couple conditonals to request the image type I wanted. This ended up looking something like:

Vue.use(VueLazyload, {
  filter: {
    progressive (listener, options) {
      if (options.supportWebp) {
        listener.el.setAttribute('lazy-progressive', 'true')
        // serve webp image from my CDN
      } else {
        listener.el.setAttribute('lazy-progressive', 'true')
        // serve progressive JPEG from my CDN
    webp (listener, options) {
      if (options.supportWebp) {
        // serve compressed webp from CDN

This approach was an easy win for us to start both lazy loading images and serving images in a next gen format.

Wrap up

There's a lot more you can do beyond what I have covered here, but hopefully this shows you some easy wins you can implement to raise your Lighthouse scores relatively painlessly.