Lighthouse SEO Lint
How the SEO ≥ 0.95 gate works in CI, and how to run it locally.
Lighthouse SEO Lint
Heycmo gates merges to main on a Lighthouse SEO score of at least
0.95 for the public marketing pages. If a change drops SEO below
0.95 on any audited URL, CI fails and the PR cannot be merged.
This catches the regressions the team actually ships:
- Missing or duplicated
<title>/<meta name="description"> - Broken
rel="canonical" - Invalid JSON-LD structured data
- Non-crawlable links (e.g.
<a>withouthref) - Bad heading order
- Blocked-from-index pages
How it works
The workflow lives at .github/workflows/lighthouse.yml and runs on
every PR that touches apps/web/**.
- Builds the static site:
npm --prefix apps/web run build - Boots
vite previewon127.0.0.1:4173 - Runs
@lhci/cli autorunagainst five representative URLs - Asserts each category score against the thresholds in
apps/web/lighthouserc.cjs - Uploads the HTML + JSON reports as a build artifact
URLs audited
| Path | Why |
|---|---|
/ | Landing page |
/tools | Tools index |
/tools/instagram-caption-generator | Most-trafficked free tool |
/tools/ai-citation-score | Recent GEO tool (sanity) |
/built-by-heycmo | Public marketing page |
/scan is not audited because it sits behind <RequireAuth> — a
Lighthouse run would score the auth redirect, not the actual scanner.
Thresholds
| Category | Threshold | Severity |
|---|---|---|
| SEO | >= 0.95 | error (blocks merge) |
| Accessibility | >= 0.90 | warn (advisory) |
| Best Practices | >= 0.90 | warn (advisory) |
| Performance | off | ignored — too noisy in CI |
Run it locally
cd apps/web
npm run lighthouseThis runs the same lhci autorun pipeline you'd see in CI: builds the
site, serves it on 127.0.0.1:4173, audits all five URLs, and writes
HTML reports to apps/web/.lighthouseci/lhr-*.html. Open them in your
browser to inspect the failures.
Updating the audited URLs
Edit apps/web/lighthouserc.cjs and add the URL to the url array.
Keep the list small (≤ 6 URLs) — each URL adds ~10s to CI runtime.
If you add a new high-traffic public page, audit it. If you add a
gated route (<RequireAuth>), do not add it.
When the gate fails
- Open the failed CI run on GitHub.
- Download the
lighthouse-reportsbuild artifact. - Open the relevant
lhr-*.htmlfile — it pinpoints the exact audit that failed. - Fix and push.
If a legitimate score drop is unavoidable (e.g. a third-party embed),
either fix the underlying issue or open a discussion before lowering
the threshold in lighthouserc.cjs.