Skip to content

Lighthouse CI Integration

Lighthouse CI Integration

Lighthouse CI is integrated into the bloqr-backend deployment pipeline to automatically audit performance, accessibility, best practices, and SEO after every production deployment.


Overview

The integration uses @lhci/cli to run Lighthouse against the live Cloudflare Workers deployment. Results are stored as GitHub Actions artifacts (no external LHCI server required).

Key properties:

  • Runs post-deploy, not in the PR gate — regressions warn but do not block deployments initially
  • Covers all four Lighthouse categories: Performance, Accessibility, Best Practices, SEO
  • Desktop throttling profile (matches developer/API user persona)
  • 2 runs per URL (median reported); bump to 3 if more reliable medians are needed
  • Stores reports as GitHub workflow artifacts for 30 days

Configuration

The full LHCI configuration lives in .lighthouserc.json at the repository root.

Key settings

SettingValueRationale
numberOfRuns2Speed over precision; increase to 3 if medians are noisy
formFactordesktopMatches primary user persona (developers, API consumers)
rttMs40 msSimulates a reasonable broadband connection
throughputKbps10 240~10 Mbps — fast broadband
cpuSlowdownMultiplier1No CPU throttling on desktop
outputDirlhci-results/Filesystem-only storage; no LHCI server needed

Workflow Triggers

The workflow (.github/workflows/lighthouse.yml) runs on two triggers:

1. workflow_run on CI (automatic)

Fires automatically when the main CI workflow (defined in ci.yml) completes successfully on the main branch — which means the Cloudflare Worker deploy step has already finished. The audited URL is the fixed production URL https://bloqr-backend.jk-com.workers.dev.

Why not deployment_status? The ci.yml deploy job uses wrangler directly and records deployments to Cloudflare D1; it does not create GitHub Deployment or Deployment Status events. The deployment_status trigger would therefore never fire. workflow_run is the correct alternative.

2. workflow_dispatch (manual)

Trigger a run manually from the Actions tab. You can supply a custom URL via the url input (defaults to https://bloqr-backend.jk-com.workers.dev).


Audit Targets

The following URLs are audited on every run:

URLRationale
/Main compiler UI — tracks LCP, CLS, and overall UX quality
/sign-inFirst page unauthenticated users encounter after the anonymous access migration; a11y ≥ 0.90 is enforced
/sign-upRegistration page — same a11y requirement; new user onboarding quality
/healthFast endpoint; should score near-perfect across all categories as a sanity baseline

The /sign-in and /sign-up pages are explicitly included because the anonymous access migration documented in docs/auth/removing-anonymous-access.md changes what unauthenticated users see when they first visit the app.


Thresholds & Assertions

Assertions are defined in .lighthouserc.json. The severity ("error" vs "warn") controls whether lhci autorun exits non-zero:

AuditSeverityThresholdReason
categories:accessibilityerror≥ 0.90A11y regressions must be caught immediately, especially after auth UI changes
uses-httpserror= 1.0Cloudflare Workers always serves HTTPS; failure indicates something is seriously wrong
is-on-httpserror= 1.0Same rationale as uses-https
categories:performancewarn≥ 0.85Permissive initially; tighten once baseline is established
categories:best-practiceswarn≥ 0.90Advisory
categories:seowarn≥ 0.90Advisory
first-contentful-paintwarn≤ 3 000 ms
largest-contentful-paintwarn≤ 4 000 ms
total-blocking-timewarn≤ 500 msRelevant for Angular compiler UI with large filter list outputs
cumulative-layout-shiftwarn≤ 0.10SSR hydration with Angular Material can cause CLS
interactive (TTI)warn≤ 5 000 ms
speed-indexwarn≤ 5 000 ms
no-vulnerable-librarieswarn= 1.0Advisory
errors-in-consolewarn0 errorsCatch JS errors in production

Note: The workflow job itself has continue-on-error: true, so even "error"-level assertion failures only mark the Lighthouse job as failed — they do not block the deployment. This is intentional for the initial integration. Remove continue-on-error once baseline scores are stable.


Reading Reports

After each successful Lighthouse run:

  1. Go to the Actions tab in GitHub.
  2. Open the relevant Lighthouse CI workflow run.
  3. The Job Summary section at the bottom contains a Markdown table with scores for each audited URL. Scores are colour-coded: ✅ ≥ 90 · ⚠️ ≥ 75 · ❌ < 75.
  4. Download the lighthouse-results artifact (retained for 30 days) to get the full JSON and HTML reports.

The JSON reports produced by @lhci/cli are standard Lighthouse result objects and can be opened with any Lighthouse viewer (e.g. https://googlechrome.github.io/lighthouse/viewer/).


Step Summary Generator (scripts/lighthouse-summary.ts)

The Job Summary table is generated by a Deno-native TypeScript script at scripts/lighthouse-summary.ts. It is invoked automatically by the workflow’s Generate step summary step via deno task lighthouse:summary.

How it works:

  1. Reads all *.json files from lhci-results/ (skipping LHCI metadata files like manifest.json).
  2. Extracts the performance, accessibility, best-practices, and seo category scores from each Lighthouse report.
  3. Converts raw 0–1 floats to integer percentages using Math.floor (never rounds up, so a score of 0.895 displays as 89, not 90).
  4. Emits a Markdown table to both stdout and $GITHUB_STEP_SUMMARY.

Running the summary generator locally (e.g., after downloading the lighthouse-results artifact):

Terminal window
# Generates a summary from lhci-results/ in the current directory
deno task lighthouse:summary
# Override the results directory
LHCI_OUTPUT_DIR=path/to/results deno task lighthouse:summary

Running Locally

First, install @lhci/cli once (adds it to your global pnpm store):

Terminal window
deno task lighthouse:install
# equivalent to: pnpm add --global @lhci/cli

Then run the audit against the live deployment:

Terminal window
deno task lighthouse:run
# equivalent to: pnpm exec lhci autorun --config=.lighthouserc.json

Or with an explicit URL override:

Terminal window
pnpm exec lhci autorun --config=.lighthouserc.json \
--collect.url="https://bloqr-backend.jk-com.workers.dev/" \
--collect.url="https://bloqr-backend.jk-com.workers.dev/sign-in" \
--collect.url="https://bloqr-backend.jk-com.workers.dev/sign-up" \
--collect.url="https://bloqr-backend.jk-com.workers.dev/health"

This requires a live URL — it cannot run against a local dev server without additional startServerCommand configuration.

Available Deno tasks

TaskCommandDescription
deno task lighthouse:installpnpm add --global @lhci/cliInstall @lhci/cli globally via pnpm
deno task lighthouse:runpnpm exec lhci autorunRun lhci autorun using .lighthouserc.json
deno task lighthouse:summarydeno run ... scripts/lighthouse-summary.tsGenerate Markdown score table from lhci-results/

Relationship to skills/seo-aeo-audit/scripts/lighthouse.sh

The skills/seo-aeo-audit/scripts/lighthouse.sh script is the manual CLI tool. It uses the standalone lighthouse binary directly and is useful for quick one-off audits or auditing arbitrary URLs from your terminal. It now supports all four categories via an optional third argument:

Terminal window
# All categories (default)
skills/seo-aeo-audit/scripts/lighthouse.sh https://example.com
# SEO only (explicit, matching previous behaviour)
skills/seo-aeo-audit/scripts/lighthouse.sh https://example.com reports/lighthouse seo

The .github/workflows/lighthouse.yml workflow is the automated CI integration that runs post-deploy. They complement each other.


Adjusting Thresholds

To tighten or loosen a threshold:

  1. Edit .lighthouserc.json in the repository root.
  2. Change the minScore / maxNumericValue for the relevant assertion.
  3. To promote a "warn" to "error", change the first element of the tuple.
  4. Commit and push — the next Lighthouse CI run will use the new thresholds.

Once the deployment has been running stably for a few weeks, consider:

  • Tightening categories:performance from 0.850.90
  • Tightening total-blocking-time from 500 ms300 ms
  • Adding a mobile job (duplicate the workflow job with formFactor: mobile settings)

Troubleshooting

lhci autorun exits non-zero in CI but the workflow job is green

This is expected when continue-on-error: true is set. Check the step output for which assertions failed. See the Thresholds & Assertions table above.

Reports are empty or missing

Ensure the target URL is reachable from the GitHub Actions runner. The deployment_status trigger fires only after a successful Cloudflare deploy, so the URL should be live.

first-contentful-paint is much higher than expected

Check for render-blocking resources or a slow Cloudflare Worker cold start. The desktop throttling profile in .lighthouserc.json uses a 40 ms RTT — cold-start latency will show up in FCP.

cumulative-layout-shift is failing after an Angular Material update

CLS is commonly introduced by Angular Material components that render at a different size after hydration. Use Chrome DevTools to identify which elements shift and apply min-height or explicit dimensions.