Share a WebPageTest result

A WebPageTest run is the best evidence there is for a performance argument, and it is evidence with a shelf life. Public-instance results are pruned; a self-hosted instance is behind a VPN and a login; and the link pasted into last quarter's ticket now resolves to nothing at all — right when someone asks whether the regression is new.

The data is recoverable while the run still exists. After that the argument is somebody's memory of a number.

Pull the run and build a page

# run it
npx webpagetest test https://example.com \
  --key "$WPT_API_KEY" --location "ec2-eu-west-1:Chrome" --runs 3 \
  --poll 5 --timeout 600 > result.json

# the pieces worth keeping
jq -r '.data.median.firstView |
  {TTFB, firstContentfulPaint, LargestContentfulPaint = .["chromeUserTiming.LargestContentfulPaint"],
   TotalBlockingTime, SpeedIndex}' result.json

The JSON also carries the URLs for the waterfall image, the filmstrip frames and the connection view. Fetch those, put them in an HTML page with the metrics table, and you have a self-contained record of the run.

Publish it

Drop the page into Comma — with the waterfall and filmstrip images alongside it, so relative references are rewritten to the uploaded copies and the page renders whole — or from CI:

curl -fsS -X PATCH "https://commareports.com/api/v1/reports/$REPORT_ID" \
  -H "Authorization: Bearer $COMMA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile html wpt.html \
        --arg t "Perf — example.com — $(date -u +%F)" '{title: $t, html: $html}')"

Images go up through POST /api/v1/reports/$REPORT_ID/assets as base64. See the API reference and publishing from CI. A routine can run the whole thing on a schedule if there is no pipeline to hang it off.

Two audiences, one page

A performance report that only contains metrics loses the people who approve the work, and one that only contains a filmstrip loses the people who do it. Include both:

  • The filmstrip. Non-engineers understand "the page is blank for 4.2 seconds" instantly and understand an LCP number never.
  • The waterfall. Engineers need the request that blocks, not the score.
  • The budget. The numbers you agreed to, next to the numbers you got.

A revision per run is the trend

PATCHing one saved report id makes the URL the standing performance page for that page template. Each run appends a revision, so the regression question — "was this always like this?" — is answered by scrubbing the history instead of by re-running an experiment against a codebase that has since changed.

That is also the answer to the expiry problem: the retention policy becomes yours.

Comments where the request is

Performance work stalls on disagreement about cause. Anchored threads keep the diagnosis on the evidence — "the 900ms is the font, not the API; we're preloading it in #3310" — so the next person reads the conclusion rather than re-deriving it from a screenshot. See commenting on HTML.

Limits

  • Entry HTML: 5 MB. Assets: 25 MB per file, 250 MB and 500 files total. A full filmstrip at 100ms intervals is a lot of frames — keep every 500ms, or the frames around the meaningful paint.
  • 60 requests/minute per token.

Try it

Comma is free — unlimited reports, unlimited commenters, unlimited revision history.

Publish a performance report →

Related