RUM waterfall charts with the W3C Resource Timing API

Posted by Phil Booth

Waterfall charts are familiar to most web developers due to their presence in various web browser developer tools. They provide a clear visualisation of when each resource on a page is loaded, how long each stage of the loading process takes and how all of the different resources interact to cause performance bottlenecks.

Usually, waterfall charts are plotted with synthetic data, either using tools like WebPageTest or by gathering the data from a development machine within your infrastructure.

However, the W3C’s Resource Timing API enables you to take performance timings of resources that are loaded by web pages running in your users’ browsers. In this post, we will see how to turn those timings into waterfall charts using the open-source projects boomerang and boomcatch.

Screenshot showing an example waterfall chart
An example waterfall chart

Collecting the data

The resource timing API returns an array of timing data from the function window.performance.getEntriesByType:

var resourceTimings;

if (window.performance && typeof performance.getEntriesByType === 'function') {
    resourceTimings = performance.getEntriesByType('resource');

Boomerang collects these and other metrics, then sends them to a server for processing.

The first step to using boomerang is to build a version of the library that contains the plugins you need. For waterfall charts, we only need to build with one plugin:

make PLUGINS="plugins/restiming.js" MINIFIER="uglifyjs -m -c"

Here we’re also providing a minification command so that the built library will be piped through UglifyJS. You can use an alternative minifier if you like.

Boomerang can then be included in your pages and invoked like so:

<!-- Edit the src attribute to point at your build of boomerang -->
<script src="boomerang-0.9.1400489333.js"></script>

<script>
    // Edit the beacon_url property to point at your server
    BOOMR.init({ beacon_url: 'http://127.0.0.1/beacon' });
</script>

This code initialises your build of boomerang with the URL of a server, which we’ll set up in the next section. After initialisation, boomerang will wait for the load or pageshow events, then collect the data and send it to the beacon URL.

Setting up the server

Boomcatch is a node.js-based server that receives performance data from boomerang. It implements an extension pipeline that enables you to plug in different validators, filters, mappers and forwarders to operate on the data before sending it to a back-end of your choosing.

To install boomcatch, you will first need to install node. Then you can get it with npm:

npm install -g boomcatch

Boomcatch comes with a waterfall mapper, which transforms resource timing data into an HTML document containing an SVG waterfall chart and a table of raw data. We’ll also use the file forwarder to store the documents in a directory on disk:

boomcatch -m waterfall -f file -D ~/waterfall

Now, each time boomcatch receives a valid request from boomerang, it will write a uniquely-named HTML file to the nominated directory.

The charts are rendered using a Handlebars template and a JSON file that specifies chart attributes such as size and colours. Both can be overridden at runtime using the command-line options --svgTemplate and --svgSettings to specify paths to alternative implementations. The default chart styles use colours from Steve Souders’ waterfall UI conventions.

Limitations

The resource timing recommendation is still fairly new, so there are a couple of things to bear in mind.

Firstly, it is only implemented in Chrome and Internet Explorer right now, so the data you collect will not be representative of all your users.

Secondly, timing data for a resource served from a different domain will only be accessible if the Timing-Allow-Origin response header indicates that it should be. In practice, this often affects the majority of resources on a page. If the hosting server is not under your control, there is nothing you can do to mitigate this, except ask the host to implement the header. Fortunately, support for this header is growing rapidly, with Facebook, Google, Akamai and Twitter among those implementing it:

Screenshot of an HTTP archive query showing support for the Timing-Allow-Origin header


Find this post useful, or want to discuss some of the topics?