Lighthouse Audits skill for Codex
Median-of-five runs and CI assertions that hold. Codex runs Lighthouse against production builds with recorded conditions, takes the median of five runs, and explains a low score through the metric weights and the Lighthouse 13 insight audits rather than the generic checklist. For CI it writes lighthouserc.json assertions on LCP, TBT, CLS and resource sizes with headroom, keeps reports out of public storage unless you agree, and handles logged-in pages.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- lighthouse-audits Installs to ~/.agents/skills/lighthouse-audits/ for every project on this machine.
curl -fsSL codexskills.dev/cli.mjs -o codex-skills.mjsnode codex-skills.mjs install lighthouse-audits The CLI also searches, updates and removes skills. Run it with no arguments to pick from a list. Needs Node 20.12+.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- --project lighthouse-audits Installs to .agents/skills/lighthouse-audits/ in the current repository. Commit it and everyone who runs Codex there gets it.
curl -fsSLO codexskills.dev/downloads/lighthouse-audits.zipunzip -o lighthouse-audits.zip -d ~/.agents/skills/ The archive holds the skill folder with its generated agents/openai.yaml. Unzip into .agents/skills/ to scope it to a repo.
& ([scriptblock]::Create((irm codexskills.dev/install.ps1))) lighthouse-audits PowerShell 5.1 or 7. Installs to %USERPROFILE%\.agents\skills\. Add -Project for the current repo.
104-line POSIX script. No sudo, no telemetry. Read install.sh
Use it in Codex
Start a prompt with $lighthouse-audits, or pick it from /skills.
You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.
What Codex reads before loading it
Runs Lighthouse and Lighthouse CI properly - repeatable settings, median-of-N runs, lighthouserc assertions on metrics and resource sizes, GitHub Actions wiring - and reads the report the way a performance engineer does, from metric weights and insights to the actual fix. Use when asked to run a Lighthouse audit, explain a low performance score, set up lhci in CI, fail a PR on a score or metric drop, or audit pages behind login with user flows.
Use it when
- Someone asks for a Lighthouse audit or to explain a performance score
- You want lhci in CI with assertions on scores, metrics or resource sizes
- Scripts that parse Lighthouse JSON broke after an upgrade to Lighthouse 13
Use something else when
- Field data already shows which Core Web Vital fails and you need the fix: use core-web-vitals
- You want budgets across bundles, APIs and Lighthouse in one CI policy: use performance-budgets
How to check the result
Before and after medians come from five runs on the same machine and settings, and lhci autorun exits non-zero when a seeded regression breaks an assertion.
The mistake it prevents
Comparing single runs from different machines or against a dev server and reading a 6-point swing as a real change.
A Lighthouse result is useful when the run conditions are stated (device, throttling, cache, Lighthouse version), the number comes from several runs rather than one, and every recommendation is traced to the metric it moves. A single local score is noise.
How the performance score is built
Lighthouse 10 and later weight five lab metrics:
| Metric | Weight | Good (mobile) | Mostly moved by |
|---|---|---|---|
| Total Blocking Time | 30% | ≤ 200 ms | Long JS tasks during load: bundle size, hydration, third-party |
| Largest Contentful Paint | 25% | ≤ 2.5 s | Server time, LCP resource discovery and size, render-blocking CSS |
| Cumulative Layout Shift | 25% | ≤ 0.1 | Unsized media, injected content, font swaps |
| First Contentful Paint | 10% | ≤ 1.8 s | Render-blocking resources, TTFB |
| Speed Index | 10% | ≤ 3.4 s | Overall visual progress |
Each metric is mapped to a 0–100 score on a log-normal curve, so the last points near 100 are expensive. Go for the heaviest failing metric first: TBT and LCP usually.
Lighthouse 13 (Oct 2025) replaced most diagnostic audits with insight audits that match
the DevTools Performance panel (lcp-phases-insight, lcp-discovery-insight,
render-blocking-insight, third-parties-insight, image-delivery-insight,
cls-culprits-insight, document-latency-insight, and others). Scoring did not change,
but scripts that read old audit IDs such as render-blocking-resources or
uses-long-cache-ttl from JSON break. Lighthouse 13 needs Node 22.19+.
Workflow
- [ ] 1. Decide the question: diagnose one page, compare before/after, or gate CI
- [ ] 2. Fix the run conditions (table below) and record them
- [ ] 3. Run 5 times, take the median run
- [ ] 4. Read metrics -> insights -> trace; map each finding to a metric
- [ ] 5. Fix, re-run with identical settings, compare medians
- [ ] 6. If gating: write lighthouserc assertions with headroom over today's median
Running it
# Needs network for npx and the target. Mobile is the default form factor.
npx lighthouse https://staging.example.com/ \
--only-categories=performance \
--output=json --output=html --output-path=./lh/home \
--chrome-flags="--headless=new"
npx lighthouse https://staging.example.com/ --preset=desktop ... # desktop profile
| Condition | Default | Rule |
|---|---|---|
| Throttling | Simulated (Lantern) slow 4G + 4x CPU | Keep it for comparisons; --throttling-method=devtools only to debug a simulation artefact |
| Machine | Whatever runs it | Same machine class for before/after; CI runners are noisy, so use medians |
| Cache | Cold | Lighthouse always clears storage unless --disable-storage-reset |
| Extensions | Local Chrome profile may have them | Headless or a clean profile; extensions inflate TBT |
| Target | Dev server | Never audit a dev server (unminified, HMR); build and serve production output |
Variance of ±5 points between runs is normal. Five runs and the median run is the
minimum for any decision; LHCI does this with numberOfRuns.
Reading the report
- Metrics: which weighted metric is furthest from good?
- Insights for that metric. LCP ->
lcp-phases-insight(which phase),lcp-discovery-insight(lazy, late discovery, no fetchpriority). TBT -> main-thread work, JS execution time,third-parties-insight,legacy-javascript-insight,duplicated-javascript-insight. CLS ->cls-culprits-insight,unsized-images. - Open the trace (DevTools “View Trace”, or save with
--save-assets) when an insight is vague. Long tasks have stack attribution there. - Translate to code: file, component, script tag, server route.
Phase-level fixes for LCP, INP and CLS are in $core-web-vitals; JS weight in
$bundle-size-reduction; third-party cost in $third-party-scripts.
Lighthouse CI
Install as a dev dependency so CI is pinned: npm i -D @lhci/cli (needs network). LHCI
bundles its own Lighthouse version; check npx lhci --version and its changelog before
asserting on insight audit IDs.
lighthouserc.json:
{
"ci": {
"collect": {
"startServerCommand": "npm run start",
"startServerReadyPattern": "ready",
"url": ["http://localhost:3000/", "http://localhost:3000/products/demo"],
"numberOfRuns": 5,
"settings": { "onlyCategories": ["performance"] }
},
"assert": {
"assertions": {
"categories:performance": ["error", { "minScore": 0.85, "aggregationMethod": "median-run" }],
"largest-contentful-paint": ["error", { "maxNumericValue": 2500, "aggregationMethod": "median" }],
"total-blocking-time": ["error", { "maxNumericValue": 300, "aggregationMethod": "median" }],
"cumulative-layout-shift": ["error", { "maxNumericValue": 0.1, "aggregationMethod": "median" }],
"resource-summary:script:size": ["warn", { "maxNumericValue": 350000 }],
"resource-summary:third-party:count": ["warn", { "maxNumericValue": 10 }]
}
},
"upload": { "target": "filesystem", "outputDir": "./.lighthouseci/reports" }
}
}
npx lhci autorun # collect + assert + upload
npx lhci collect --staticDistDir=./dist # static sites: LHCI serves the folder itself
- Prefer explicit assertions over the
lighthouse:recommendedpreset; presets reference audit IDs that change between Lighthouse majors. upload.target: "temporary-public-storage"publishes reports to a public URL. Ask the user before enabling it; staging pages can contain unreleased content. Default tofilesystemplus CI artifacts, or a self-hosted LHCI server.- Set thresholds from today’s median with headroom (score minus 5, metrics plus 10–15%),
then ratchet. A gate that flaps gets disabled. See
$performance-budgets.
GitHub Actions (pin action versions to a commit SHA in real use):
- run: npm ci && npm run build
- run: npx lhci autorun
- uses: actions/upload-artifact@v4
if: always()
with: { name: lighthouse, path: .lighthouseci }
Pages behind login or after interaction
- LHCI
collect.puppeteerScriptruns a script before each URL; use it to log in with a test account from the project’s fixtures, never a real user’s credentials. - Lighthouse user flows (
startFlowfrom thelighthousenpm package with Puppeteer) measure navigation, timespan (interactions, gives INP-like data) and snapshot modes in one report. Use timespan mode to audit a click-heavy flow.
Gotchas
- PageSpeed Insights lab numbers come from Google’s servers and differ from your local run; its field section is CrUX and is what Search uses.
- Score 100 on desktop with simulated throttling says little about mid-range Android.
- A redirect on the audited URL (http -> https, trailing slash) adds to every metric. Audit the final URL.
- Cookie banners and interstitials change LCP and CLS. Decide whether to audit with or without consent state, and keep it consistent.
- Do not chase the “unused JavaScript” byte count blindly; split code only on routes where TBT or LCP is failing.
Report template
## Lighthouse: <URL> (<mobile|desktop>, Lighthouse <version>, median of 5)
Score: 62 (before) -> 81 (after)
| Metric | Before | After | Weight |
|---|---|---|---|
| TBT | 820 ms | 240 ms | 30% |
| LCP | 4.1 s | 2.6 s | 25% |
Top findings -> fixes:
1. <insight id>: <what it showed> -> <code change, file>
Conditions: <machine, throttling, server, commit>
Field data (CrUX/RUM) still pending: <yes/no> What the zip contains
SKILL.md plus the interface file below. Nothing runs on install.
agents/openai.yaml
Gives the Codex app a display name, a one-line description and a starter prompt for this skill.
interface:
display_name: "Lighthouse Audits"
short_description: "Median-of-five runs and CI assertions that hold"
default_prompt: "$lighthouse-audits Why is our Lighthouse performance score 58 on mobile and what should we fix first?" About this skill
Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.