How to read a Web Page Test waterfall chart

So I often find myself looking at WebPageTest (WPT) waterfall charts, but as I seem to have the memory of a chimpanzee (not a goldfish, that’s a myth) I tend to forget some of the details and what they all mean. So I decided to pull together many bits of information into a single blog post I can then refer to at a later date. If you find it useful, or think I’ve forgotten anything, please let me know.

Basic Layout

Here’s the basic layout of the waterfall chart user interface:

Basic layout of the Web Page Test waterfall chart includes the 1:key, 2:request list, 3:request timeline, 4:CPU utilisation, 5:Bandwidth in, 6:browser main thread, 7:page is interactive.

1 - Key

The key shows three types of information:

  1. Information about the connection status (DNS lookup, connection established, SSL negotiation)
  2. The type of resource being requested (e.g. HTML, images etc)
  3. Miscellaneous events (wait, JavaScript execution)

Each resource has 2 colours, a light shade and a dark shade. The light shade signifies the point at which the browser has made the request for the resource. The dark shade is the point at which the resource is actually downloading. See this comment from Pat Meenan for more information.

The “wait” visualisation is a new addition to WPT. It shows you the time between when the browser first discovered the resource on the page, up to when the request for the resource was made by the browser to the server.

2 - Request list

A list of assets the browser has discovered on the page and the order in which they were requested. Note the request number on the far left, as well as the yellow lock if the request is being made over a secure connection (HTTPS).

3 - Request timeline

The timeline shows the time along the horizontal (x) axis verses each request made on the vertical (y) axis. From this you can see the lifecycle of a request made by the browser. From discovery (wait), through to request being made, and finally to asset being download.

Ideally you want to make sure this timeline covers as little time as possible, as this indicates better overall performance. The less time the timeline covers, the quicker the page loads for a user.

4 - CPU Utilisation

A simple graph showing the CPU utilisation of the browser process running on the device. It displays how much CPU the current webpage is using at any point in time. It ranges from 0 - 100% utilisation. See this comment from Pat Meenan for more information.

5 - Bandwidth In

This is an indicator of when data is coming flowing into the browser. The visualisation is helpful to see when the browser is doing useful work vs wasted time. The absolute scale can be ignored, as it isn’t very accurate. Use the “Capture network packet trace (tcpdump)” option in the advanced tab on the WebPageTest homepage if you want more accurate results. See this comment from Pat Meenan for more information.

6 - Browser Main Thread

This graph visualises what the browsers main thread is doing at a specific point in time. The y-axis shows the percentage from 0 - 100%. The colours were copied from the Chrome DevTools CPU graph (under the performance tab). Here’s what each of the colours mean:

  • Orange - Script parsing, evaluation and execution  
  • Purple - Layout  
  • Green - Painting  
  • Blue - HTML parsing  

Using this graph it is possible to see if the CPU is becoming a bottleneck in one of the above areas.

7 - Page is Interactive

This graph gives you an indication of when the main thread is blocked. The red blocks indicate that the main thread has been blocked for 100ms (which will also block inputs like button presses). Green indicates the thread isn’t blocked. Note: it still may be possible to scroll during red blocked phases, as scrolling is usually handled off the main thread for most browsers. See this comment from Pat Meenan for more information.

Vertical lines

You can see the key for each of the coloured vertical lines below the “Waterfall View” header as seen below:

Key for the vertical lines displayed on the timeline. From left to right: Start render, RUM first paint, DOM interactive, DOM content loaded, On load, Document complete.

But what do each of them mean?

Start Render - Green line  

This is the first point at which a user will see pixels painted to the page. The pixels could be from anything at all (background colours, borders etc), not necessarily content. Before this point the screen was blank. This metric is measured by analysing individual video frames of the page load. See comment from Pat Meenan for more information.

RUM First Paint - Light green line  

This is the point where the browser renders anything to the screen that is visually different from before navigation (the blank screen for WPT). This metric is reported via the browsers API, so when it thinks it painted the first content. Because of this, the line is only visible if the browser supports the Paint Timing API.

DOM Interactive - Yellow line  

The point at which the browser has finished parsing all the HTML, and DOM construction is complete. Unfortunately it’s not a reliable metric.

DOM Content Loaded - Pink line  

The point at which the HTML has been loaded and parsed, and the browser has reached the end of the document. All blocking scripts have been loaded and run. The DOM and this point is completely defined. See comment from Pat Meenan for more information.

On Load - Lavender line  

The point at which the window load event fires. All objects are in the DOM and all images and scripts have finished loading.

Document Complete - Blue line  

The point where the onload event has fired and all the static image content has loaded. Content changes that are triggered by JavaScript execution may not be included.

Horizontal timings

So let’s now concentrate on the request timeline (3). What do the horizontal blocks mean and what metrics do they refer too? Well, if you click on an individual request you will see a popup with a lot more information, as seen in the example below:

By clicking on an individual request in WebPageTest it will give you much more information including timing details, request details, response details and if enabled when testing, the original response body.

So lets take a look at a few of the requests from this waterfall view, as it gives us a number of quite varied requests to look at.

Request 1 - The HTML

Here the browser is requesting the HTML document, so at this point in time it is also having to setup the connection to the server. In the request details we are given the following timings:

  • Discovered: 0.011 s
  • Request Start: 0.116 s
  • DNS Lookup: 27 ms
  • Initial Connection: 25 ms
  • SSL Negotiation: 43 ms
  • Time to First Byte: 315 ms
  • Content Download: 40 ms

I’ve annotated the request to show what each of these timings mean:

Request number one with timings annotations added, including all the timings listed above.

Adding the DNS, Initial Connection, SSL, Time to First Byte and the Content download times gives you the 450ms that is displayed directly after the request finishes.

It’s worth noting that WPT follows a specific convention in the request details panel:

  • If the time corresponds to a duration, it is measured is milliseconds (ms), e.g. the DNS lookup took 27ms.
  • If the time corresponds to a starting point, it is measured in seconds (s), e.g. the request started at 0.116s.

Request 7 - A third-party JavaScript file

This request is different from the other requests examined because the file is coming from a different domain. The request details give the following timings:

  • Discovered: 0.473 s
  • Request Start: 0.702 s
  • DNS Lookup: 28 ms
  • Initial Connection: 39 ms
  • SSL Negotiation: 153 ms
  • Time to First Byte: 48 ms
  • Content Download: 9 ms

Notice how the browser needs to go through the whole connection negotiation again (DNS, Connection, SSL) because the file exists on a different domain. This adds a fair chunk of time to the request (28 + 39 + 153 = 220ms).

Request 7 loads a JavaScript file from a third-party domain. This causes a new TCP connection to be established. 200ms after the JavaScript is downloaded the graph shows JavaScript execution that is also visible on the Browser main thread.

The other interesting point about this request is the script executes around 200ms after the download is complete. There’s no information about this execution in the details panel, but you can see it in the waterfall: light pink lines after the request and orange in the “Browser Main Thread” panel which signifies “Script parsing, evaluation and execution”.

Request 15 - A sponsor PNG

With this request the browser has discovered a PNG image and requests it from the server. In the request details we are given the following timings:

  • Discovered: 0.652 s
  • Request Start: 0.824 s
  • Time to First Byte: 214 ms
  • Content Download: 28 ms

Wait time is calculated by subtracting the discovered time from the request start time. The wait time is the time taken from when the browser first finds the asset, to the time when it has the capacity to send a request to the server.

Request 15 downloads a PNG image. The waterfall now includes the new waiting period from when the asset was discovered by the page, to when the browser makes the request.

The duration after this request is the time taken from the request being made, to when the request is completed (Time to First Byte + Content Download). Since a connection to the domain has already been established, no need for DNS, Connect, SSL.

Request 23 - GIF file moved

Although request 23 looks quite unremarkable, there are a couple of things going on. The background of the request is yellow. This is to signify a server response status code that isn’t the usual 200. In this instance it is a 302 status code, which signifies the GIF file has been temporarily moved. In fact all responses with a 3xx status code will have a yellow background. The request details show the following information:

  • Error/Status Code: 302
Request 23 shows how WPT displays 302 redirects in the form of a highlighted bar in yellow and a different status code after the request has completed.

Notice how request 23 doesn’t require a TCP connection to be established. This is because it has already happened to this domain on request 20.

A 4xx status code is displayed in a similar way, only the background is red, like in the example below (note this image is from a different test):

Request 7 shows what happens on a WebPageTest waterfall graph when it encounters a status code starting with a 4xx (error). The background of the request is coloured red, and the status code at the end displays (404).

The request details show the following information:

  • Error/Status Code: 404

Notice the colour of the returned response in this instance. Rather than being the expected purple colour for an image, it is blue signifying that it is a HTML page. Or, in other words, it is the server responding with the 404 page.

Common scenarios

Here’s a list of common patterns seen in a WPT waterfall. I will add more of these over time as I encounter them.


Online Certificate Status Protocol (OCSP) is an internet protocol used for obtaining the revocation status of SSL certificates. A way for a browser to certify a certificate is to connect to an OCSP server for verification. When this happens Web Page Test will show you in the waterfall as seen below:

OCSP requests seen in Web Page Test appear before the request for the HTML. These request add a large amount of time to the SSL negotiation and the HTML download.

This OCSP check is bad for performance. The verification requires a DNS lookup and an initial connection to the OCSP server. Only once the certificate has been verified can the original SSL negotiation take place to the original domain. As you can see in the image, the whole timeline is being pushed back 2 seconds before the HTML page can even be downloaded. If you notice this on your Web Page Test timelines you should look into enabling OCSP stapling on your server. Note: If you are using Extended Validation certificates (EV) OCSP stapling won’t fully solve the issue, see this technical Twitter thread for more details.


Preconnect is part of the Resource Hints Working Draft. It allows a developer to give the browser a “hint” that a domain in the future will need to be connected too. By connecting to the origin early, the connection won’t need to be established later in the waterfall, thus allowing assets from said domain to be requested and downloaded quicker when they are required.

The image shows the preconnected domain establishing the connection earlier than required, before the asset is requested. This preconnect allows the request to happen immediately.

As you can see in the image above, the preconnect looks to be “floating” in the timeline. It happens way before the actual request for the image is made. This is the browser using the preconnect hint to connect ahead of time before it is required. For more information on the preconnect hint I recommend reading this blog post by Andy Davies.


Like the preconnect example above, DNS Prefetch is part of the Resource Hints Working Draft. It gives a developer the ability to tell the browser that a DNS lookup is going to need to happen for a specific domain in the future. So instead of waiting, start the lookup immediately. By the time the domain is actually required the browser will only need to complete the TCP handshake, and optional TLS negotiation. It looks similar to the preconnect example above, in that it is “floating” in the timeline. But this time only the DNS lookup is visible.

The waterfall shows the dns-prefetch occur quite some distance from where it would usually happen (with the TCP and SSL negotiation). It is also worth noting where it occurred in the timeline, directly after the HTML download completed.

Notice where the dns-prefetch occurred in the timeline: almost immediately after the HTML has finished downloading and is parsed. It is easy to see the difference if you compare it to the connection negotiations happening in requests 5 and 7, where preconnect is being used.


Preloading is a W3C Candidate Recommendation and is used to increase the loading priority of selected assets. A developer can tell the browser: “this resource will absolutely be needed soon, so load it right away”. This technique is often used when loading web fonts.

When loading a web font the browser first needs to download the HTML and the CSS, then parse both to create the render tree. Only at this point can the browser request the font. This can lead to a Flash of Invisible Text (FOIT) and Flash of Unstyled Text (FOUT). A way around this issue is to request the web font file immediately using the preload hint.

With Preloading

A preloaded request comes directly after the HTML download starts (request number 2), when the browser parses the <head>. The request for this asset is started as soon as it is discovered.

Without Preloading

The usual font loading occurs after the CSS has downloaded and is parsed. You can see the font has request number 11, verses number 2 when preloaded.

If you compare both of the images above you will see the request for the preloaded WOFF2 font is made as soon as the HTML starts to be downloaded at request number 2 (dark blue strip). The browser parsed the <head> tag immediately, saw the preload hint and made the request straight away. Compare this to the way a browser usually downloads the font by waiting for the HTML and CSS to be downloaded and parsed. Only at the point when this is complete can the WOFF2 request be made. As you can see from the image, when preloading isn’t used the font has request number 11. I’ve written more about font preloading here if you are interested.

HTTP/1.1 vs HTTP/2

HTTP/2 is the next iteration of the HTTP protocol after HTTP/1.1. Due to the fact that HTTP/2 uses a single TCP connection and multiplexes files over this single connection, it is easy to spot the difference in the resulting timelines.


HTTP/1.1 waterfall showing the stepped image requests from the page due to multiple TCP connections having no knowledge of each other.


HTTP/2 waterfall showing the simultaneous image requests by the browser. The browser will stream the image data back via a single connection.

A browser using HTTP/1.1 requests images via separate TCP connections, and this tends to happen at slightly different times (hence the stepped nature of the timeline). A browser using HTTP/2 on the other hand requests all the images at the same time. It is then up to the server to decide when the images will be sent back to the browser, and in what order.

Firefox enhanced tracking protection

Firefox enabled enhanced tracking protection by default as of version 69 (June 2019). The agents on WebPageTest updated around the same time. In some rare cases the tracking protection requests could be seen in the WPT waterfall (request 1-3):

Firefox enabled enhanced tracking protection in version 69. A DNS lookup and the requests could be seen before the initial connection in some rare cases.

According to Pat Meenan these requests should now be filtered out by default, so they will never be seen in the waterfall chart.

Service worker precaching

The use of service workers is gradually increasing, and one of the many features they allow is a fine-grain control on what assets are cached and for how long. They also give a developer the ability to precache files for future use (e.g. for offline capabilities). An important detail to remember when precaching assets using a service worker is the browser may need to download the same files twice. Once for the HTTP cache (the standard browser cache), and again for the service worker cache (Cache API). They are two separate caches, and don’t share assets. These duplicate requests can be seen in a WebPageTest waterfall chart:

The two sets of identical assets are downloaded twice, once for the HTTP cache then again for the service worker cache.

In requests 17 and 18 you can see the service worker JavaScript being requested, downloaded, and initialised. Immediately after this, the service worker looks through it’s precache JSON file and requests any assets listed. Note: In the example the Workbox library is being used to simplify the service worker workflow.

Chrome Stair-step

Chrome has included a prioritisation technique that is named due to the pattern it creates in waterfall charts. It involves Chrome examining the assets in the <head> tag (before the page even has a <body>), and requesting, downloading, and parsing these requests first. The browser even goes so far as to delay requests for assets in the body until the <head> requests are complete. It is easier to see this stepping in a HTTP/1.1 graph (although it also occurs in HTTP/2):

Chrome stair-stepping occurs when the browser delays requests from the body element in favour of completing the requests from the head element. This can be seen in the WPT waterfall as a distinct step in the timings.

In the above image from the BBC News website, the 8 out of the first 9 requests are made for assets in the <head>, with only 1 request to a JavaScript file located in the <body>. The “step” isn’t very long in terms of duration, only around 200ms. But it gives the browser enough time to concentrate all CPU and bandwidth on downloading and parsing these assets, so the <head> is setup and ready to go before the <body> assets are downloaded and parsed.

Not much has been written about this “layout-blocking” phase in Chrome, but it can be seen in detail in the Resource Fetch Prioritization and Scheduling in Chromium document by Pat Meenan, and also in Chrome’s resource scheduler source code.

More to be added soon…

As I discover more common timeline scenarios I will add them here. If you know of any common ones that are missing, please do let me know!


So there you have it, a bit of a brain dump into a blog post about some of the aspects of WebPageTest that I’ve found a little mysterious. As this has been a bit of a learning exercise for me too, if there is anything I have misinterpreted, please do tweet me.

If you would like to learn a lot more about WebPageTest, I highly recommend the book: “Using WebPageTest” by Rick Viscomi, Andy Davies, Marcel Duran.

Post changelog:

  • 11/10/19: Added waterfall for Firefox enhanced tracking protection scenario.
  • 12/10/19: Added service worker precaching scenario.
  • 13/10/19: Added Chrome Stair-Step scenario.
  • 14/10/19: Added the dns-prefetch scenario.
  • 15/10/19: Added note about OCSP stapling and EV certificates (thanks @RyanTownsend for flagging).