Website Speed Testing & Monitoring: Build it for Free
Speed means nothing without a point of reference.
Brian Louis Ramirez
According to WebPageTest:
New API keys are not currently available for the public WebPageTest instance. There will be an option for API keys again in the near future.
Speed means nothing without a point of reference.
So you’re aware of how important page speed is to users and how web performance affects your business. You’ve read about establishing a page speed budget at your organization. And after running some Google Lighthouse audits in Chrome or plugging a couple of URLs into online tools like Webpagetest, Pingdom or Yellowlab.
But now you want to test more pages, perhaps set some cookies, tweak testing conditions such as mobile emulation and network speed. Or you want to hone in on particular metrics such as Time to Interactive, First Meaningful Paint, Load Time or Bytes HTML/CSS/JS. And you want to automate the whole thing.
You can turn to some excellent monitoring tools like Speedcurve — but you’ll have to fork out some big buck$$$.
Or you can also monitor smaller projects on your local machine for nix.
In this article, I’ll explain how I test and monitor webpage performance using Webpagetest, Google Lighthouse, InfluxDB and Grafana — fully flexibly and for free.

Grafana is perfect for displaying web perf metrics and even setting alerts
Warning: My solution is very hacky — my code is crying for a good refactoring. But it works.
TL;DR

Use this simple setup on your local machine to test webpage performance and monitor key metrics
- Write a Node.js script that uses the Webpagetest API for running web performace tests
- The Webpagetest API is flexible: You can set test parameters (e.g. network conditions, number of test runs), set cookies and download videos and keyframe screenshots of a page loading
- Write specific web performance metrics to an InfluxDB database running on your local machine
- Display your metrics in Grafana running on your local machine
- Automate testing either with a bash script or a cron job
1. Get InfluxDB Up and Running
First off, install InfluxDB.
Then, in your terminal, if you enter influx
with InfluxDB running, you should get the following output:
$ influx
Connected to http://localhost:8086 version v1.7.x
InfluxDB shell version: v1.7.x
Enter an InfluxQL query
>
Now create a new database webpagetest
.
> create database webpagetest
2. Get a Webpagetest API key
Now get your free Webpagetest API key.
With it you can run 200 tests per day — which is more than enough for personal use and small projects.
3. Write a Node.js Script to Run a Webpagetest
You’ll need Node installed on your machine.
Create a document for your Node script and save it as webpagetest.js
.
Declare Variables and Include Modules
First off, in webpagetest.js
, declare a variable testURL
for the URL to the page you want to test, and a variable pageName
which you can use to name your test.
// Set the following variables for the page to be tested
let testURL = process.argv[2];
let pageName = process.argv[3];
Include modules and set a few variables for later. Insert your Webpagetest API key in the variable key
.
// Import modules and other test variables
const WebPageTest = require(‘webpagetest’);
const fs = require(‘fs’);
const download = require(‘download-file’);// Insert your key here
const key = ‘XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX’;
const wpt = new WebPageTest(‘www.webpagetest.org', key);// Import Influx and set the database to "webpagetest"
const Influx = require(“influx”);
const influx = new Influx.InfluxDB({
host: “localhost”,
database: “webpagetest”,
port: 8086
});
module.exports = influx;// Other variableslet path = ‘./results/_tmp/’;let videoDownloadURL = ‘https://www.webpagetest.org/video/download.php?id=';let filmstripURL_start = ‘https://www.webpagetest.org/video/filmstrip.php?tests=';let filmstripURL_end = ‘-r:1-c:0&thumbSize=200&ival=500&end=visual&text=ffffff&bg=000000’;
Set Test Options
The great thing about Webpagetest is how much control you have over how the tests are run.
Speedy pages are especially important on mobile devices in a mediocre mobile network. So I set the test options accordingly and tell Webpagetest to also give me a video of the test page loading and to perform a Google Lighthouse audit:
const testOpts = {
emulateMobile: true,
location: “ec2-eu-central-1”,
firstViewOnly: false,
connectivity: ‘3GFast’,
pollResults: 5,
video: true,
lighthouse: true
}
Set Cookies (optional)
Sometimes you want to see how fast a page loads for a logged-in user or a user with certain settings.
With wpt.scriptToString
, you can tell Webpagetest to set cookies and navigate to a specific URL.
const script = wpt.scriptToString([
{ setCookie: [‘https://www.example.com/', ‘cookie-consent=true’] },
{ navigate: testURL },
‘waitForComplete’
]);
Run a Test
Now comes a monster function, which you sure as hell can refactor. In wpt.runTest()
you can a) run tests, b) write test data to InfluxDB, and c) download a test video and filmstrip.
First, call the runTest
function on wpt
and use script
and testOpts
as arguments. Then write some messages to the console and declare some variables for later.
wpt.runTest(script, testOpts, (err, result) => {
if (err) throw err;
console.log(‘########################################’);
console.log(err || ‘Test successful for ‘ + testURL);
let date = result.data.completed;
let fileName = path + date + “ — “ + pageName + ‘.json’;
let testID = result.data.id;
console.log(‘Test ID: ‘ + testID);
let stats = JSON.stringify(result.data, null, 2);
You can optionally save the results of the Webpagetest and Lighthouse audit as JSON to a local directory:
// Optional for saving JSON test results to a local directory
fs.writeFile(fileName, stats, (err) => {
if (err) throw err;
console.log(“Data for “ + pageName + “written to file: “ +
fileName);
});
Write Test Results to InfluxDB
Still within the monster runTest
function, you set and declare variables that are used for writing test results to InfluxDB.
// Variables for writing test results to InfluxDB. Set the date to a format that InfluxDB understands.
date *= 1000000000;
let firstView = result.data.runs[“1”].firstView;
You can take a look at the JSON output of a test for the performance metrics you need.

Example JSON output from Webpagetest
Then declare variables for the metrics you need, e.g.:
// The metrics you want to monitor
let firstMeaningfulPaint = firstView.firstMeaningfulPaint;
let loadTime = firstView.loadTime;
let firstInteractive = firstView.FirstInteractive;
let bytesInDoc = firstView.bytesInDoc;
let requestsDoc = firstView.requestsDoc;
let fullyLoaded = firstView.fullyLoaded;
Then call method writePoints
on influx
that writes those metrics to your Influx database.
// Call a method that writes test results to InfluxDB
influx
.writePoints([
{
measurement: “webpagetest”,
tags: {
pageName: pageName,
run: 1
},
fields: {
firstMeaningfulPaint: firstMeaningfulPaint,
timeToInteractive: firstInteractive,
bytesInDoc: bytesInDoc,
fullyLoaded: fullyLoaded,
requestsDoc: requestsDoc,
loadTime: loadTime
},
timestamp: date
}
])
.then(() => {
return influx.query(`
select * from webpagetest
order by time desc
`);
})
.catch(err => {
console.error(`Error creating Influx database!`);
});
Download Video and Filmstrip (optional)
You can download an MP4 video and a “filmstrip” of the page loading.
// Video Options
var videoOptions = {
directory: path,
filename: date + “ — “ + pageName + “.mp4”
}// Filmstrip options
var filmstripOptions = {
directory: path,
filename: date + “ — “ + pageName + “.png”
}// Method to create video of the page loading
wpt.createVideo(testID, testOpts, (err, data) => {
console.log(err || data);
let videoId = data.data.videoId;
videoDownloadURL += videoId;
setTimeout(function () {
download(videoDownloadURL, videoOptions, function (err) {
if (err) throw err;
console.log(‘########################################’);
console.log(“Video download URL for “ + pageName + “: “ + videoDownloadURL);
console.log(‘########################################’);
})
}, 5000);// Download the filmstrip
var filmstripURL = filmstripURL_start + testID + filmstripURL_end;
download(filmstripURL, filmstripOptions, function (err) {
if (err) throw err;
console.log(‘########################################’);
console.log(“Filmstrip download URL for “ + pageName + “: “ + filmstripURL);
console.log(‘########################################’);
}) });
});
4. Set Up Grafana
Download and install Grafana, then open http://localhost:3000
in your browser.
Set up InfluxDB as your data source
Choose “InfluxDB” as your data source type, then set http://localhost:8086
as the URL.
Under “InfluxDB Details”, select “webpagetest” to use as the database.
Click “Save & Test” at the bottom of the page.

Create a new dashboard and add a graph
Go over to your “Home Dashboard” and click on “Create your first dashboard”. A new dashboard will open.
Then click on “Graph” to add a graph to a new panel.
Select metrics for the graph

Click on “Panel Title” above the empty graph, then select “Edit”.
In the “Data Source” dropdown, select “InfluxDB”.
Now, add a query next to the “A” that will display a metric for a specific page.
For example, if you want to see how the Time to Interactive for Page A progresses over time, use a query like this:

To get rid of the default “mean()” attribute from “time($_interval)”, click on it and select “remove.” Then you can click the plus icon and select the attribute “last()”.
Feel free to duplicate queries and change the pageName
for each page you want to display in the graph.
Edit Axes and Display settings
In the Axes panel, select “milliseconds (ms)” for “Unit”.

In the Display panel, make sure “Null value” is set to “connected”.

Then click on the little “x” to exit Edit mode, make sure the time range includes your data points, and save your dashboard.

Voilà!
5. Automate Testing
You can run single tests via command line by calling webpagetest.js
and adding a URL and a “page name” (how you want to label test output):
$ node webpagetest.js “https://www.example.com/page-name" pageName
I run multiple tests in a bash script, adding additional commands with other URLs and page names:
#! /bin/bash# Move to the directory where ‘webpagetest.js’ is located
cd /Users/<user>/webpagetest/# Run a test per page
node webpagetest.js “https://www.example.com/page-name-1" pageName1 &
node webpagetest.js “https://www.example.com/page-name-2" pageName2 &
node webpagetest.js “https://www.example.com/page-name-3" pageName3
That bash script can be executed either by setting up a cron job or using Automator on Mac.
Upvote
Brian Louis Ramirez
UX & Design, born in California, made in Germany. Loves music, songwriting and running.

Related Articles