Share an Artillery load test report
Artillery's output is a summary table in a terminal and, if you asked for it, a JSON file. The summary scrolls away. The JSON goes into an artifact bucket.
And load test results have an unusually short useful life for an unusually important reason: they exist to settle an argument — is this fast enough, and did the change help? — which means they need to be readable by the people having the argument, most of whom were not in the terminal.
The v2 situation, stated plainly
Artillery v1 had a built-in reporter:
artillery run -o out.json test.yml
artillery report out.json # → out.json.html, one self-contained file
v2 removed it. The report command is gone, and the official path is
Artillery Cloud. If you are on v2 and want a local HTML artifact, you
generate it from the JSON:
artillery run --output report.json test.yml
report.json contains the aggregate and the intermediate buckets — enough
to render latency percentiles over time, error counts by response code,
and per-scenario breakdowns. A small template over it, or one of the
community converter packages, gets you a page.
That is genuinely more work than v1. It is also the honest state of the tool, and worth knowing before you go looking for a flag that no longer exists.
Publish it
artillery run --output report.json test.yml || true
# …render report.json → report.html…
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 report.html \
--arg title "Load test — $(git rev-parse --short HEAD)" \
'{title: $title, html: $html}')"
One call, no assets, if the page is self-contained — which it should be,
since a load test report is mostly a few charts over a modest amount of
data. Use a scoped token (reports:write) from CI
secrets and PATCH a saved report id so one URL accumulates a revision
per run. See publishing from CI.
The || true matters if you use Artillery's threshold checks — a failed
SLO exits non-zero, and that is exactly the run worth publishing.
Charts stay charts
If your rendered page uses a charting library, keep it self-contained
rather than CDN-linked. Scripts run inside a sandboxed iframe
(allow-scripts, no allow-same-origin), so an inlined chart library
boots and stays interactive — hover for the value at a timestamp, zoom
into the window where latency turned. See
interactive HTML reports.
Anything the page tries to fetch from your internal network at view time will not resolve; bake the data into the file.
Argue about the p99 next to the p99
This is the whole reason to publish rather than paste:
- "p99 is 1.2s" — attached to the chart, someone can point out that the spike is the connection pool warming and the steady state is 300ms.
- "the error rate is 2%" — anchored to the step, someone notes those are all 429s from a rate limiter that isn't in production.
- "this run isn't comparable" — because the fixture data was smaller. Worth recording on the run itself, not in a reply three days later.
Select the number, leave a thread, and it stays anchored across revisions. See commenting on HTML.
The comparison is the product
A single load test result is nearly meaningless. The useful artifact is this run versus the one before the change.
PATCHing one report id gives you that for free: every run is a revision
at the same URL, and any two revisions can be diffed. A performance
regression conversation becomes "here are the two runs" rather than two
screenshots of two terminals.
For a nightly baseline, a routine re-runs it on a cron and posts the refreshed result as a new revision.
Limits
- Entry HTML: 5 MB — generous unless you inline every raw sample; publish the aggregates and the intermediate buckets, not the full request log. Assets: 25 MB per file, 250 MB and 500 files total.
- Scripts run, sandboxed — no same-origin access.
- 60 requests/minute per token.
Try it
Comma is free — unlimited reports, unlimited commenters, unlimited revision history.