Perf — sitespeed.io
Core Web Vitals monitoring with sitespeed.io (real Chrome, official Docker image). The job fails when the performance budget is exceeded, so GitHub's failure email is the alert. Results are kept as artifacts and, optionally, appended to a CSV on a history branch.
Usage
yaml
on:
schedule:
- cron: "17 5 * * *"
workflow_dispatch:
jobs:
sitespeed:
uses: KevinDeBenedetti/github-workflows/.github/workflows/perf-sitespeed.yml@main
permissions:
contents: write # history job pushes to the history branch
with:
device: bothThe caller needs two files:
text
perf/urls.txt # one URL per line
perf/budget.json # {"budget": {"googleWebVitals": {"largestContentfulPaint": 2500,
# "cumulativeLayoutShift": 0.1, "totalBlockingTime": 300}}}Inputs
| Input | Type | Default | Description |
|---|---|---|---|
urls-file | string | perf/urls.txt | URLs to test, one per line, in the calling repo |
budget-file | string | perf/budget.json | sitespeed.io budget JSON in the calling repo |
iterations | number | 5 | Runs per URL (metrics are the median) |
device | string | desktop | desktop, mobile, or both (matrix of the two) |
sitespeed-image | string | sitespeedio/sitespeed.io:<tag>@sha256:… | Image pinned by tag + digest, bumped by Renovate |
history-branch | string | perf-history | Branch receiving history.csv (orphan if missing). Empty disables |
runner | string | '"ubuntu-latest"' | Runner labels as JSON |
Jobs
sitespeed(one per device) — checkout, validate inputs, run the container (--mobilefor mobile), extract the median LCP/CLS/TBT, write a step summary, uploadsitespeed-result-<device>(90 days). Extraction and upload useif: always()so they run even when the budget failed.history(only ifhistory-branchis set) — downloads the artifacts and appendsdate,url,device,lcp,cls,tbtrows tohistory.csvon the history branch. Hascontents: write, scoped to this job only. A single job writes after the matrix, sodevice: bothcannot cause concurrent-push conflicts.
Notes
- Do not use a
k3s-*runner. Testing from the cluster's own network skews LCP and TTFB; the default GitHub-hosted runner is the right vantage point. - The caller's
permissions:cap the called workflow. Grantcontents: writeon the calling job when the history is enabled; withhistory-branch: ''contents: readis enough. - The budget file must wrap the thresholds in a top-level
"budget"key. - Start with loose thresholds and tighten them after a week of data.
- No dashboard: alerting is the failure email, history is the CSV + artifacts.
Run locally
bash
docker run --rm --shm-size=1g -v "$(pwd)/sitespeed-result:/sitespeed.io" \
sitespeedio/sitespeed.io:<tag> https://example.com/ -n 5 -b chrome \
--budget.configPath budget.json