Setting Up Automatic Lighthouse Report for Each Deploy
Manual Lighthouse runs happen after something breaks. Automatic runs on each deploy flip the logic: regressions visible before reaching production with exact commit that caused them.
Minimal Stack
Minimum: CI/CD (GitHub Actions, GitLab CI, CircleCI) + Lighthouse CI CLI + storage. Optional: LHCI server for history and comparison.
Installation and Setup
npm install --save-dev @lhci/cli
Config file .lighthouserc.js:
module.exports = {
ci: {
collect: {
url: [
'http://localhost:3000/',
'http://localhost:3000/about',
'http://localhost:3000/catalog',
'http://localhost:3000/product/test-product',
],
numberOfRuns: 3,
startServerCommand: 'npm run start:ci',
startServerReadyPattern: 'ready on',
startServerReadyTimeout: 30000,
},
assert: {
assertions: {
'categories:performance': ['warn', { minScore: 0.8 }],
'categories:accessibility': ['error', { minScore: 0.9 }],
'categories:best-practices': ['warn', { minScore: 0.85 }],
'categories:seo': ['error', { minScore: 0.9 }],
'first-contentful-paint': ['warn', { maxNumericValue: 2000 }],
'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
'total-blocking-time': ['warn', { maxNumericValue: 300 }],
'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
'speed-index': ['warn', { maxNumericValue: 3400 }],
},
},
upload: {
target: 'temporary-public-storage',
// or own LHCI server:
// target: 'lhci',
// serverBaseUrl: 'https://lhci.example.com',
// token: process.env.LHCI_TOKEN,
},
},
};
GitHub Actions Workflow
name: Lighthouse CI
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Run Lighthouse CI
run: |
npm install -g @lhci/[email protected]
lhci autorun
env:
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
LHCI_TOKEN: ${{ secrets.LHCI_TOKEN }}
LHCI_GITHUB_APP_TOKEN needed for LHCI to leave status checks on PR with report link in GitHub interface.
Self-Hosted LHCI Server
temporary-public-storage convenient for start, but stores data 7 days only and doesn't allow comparing PR with baseline. For team use, set up own server:
# docker-compose.yml
services:
lhci-server:
image: patrickhulce/lhci-server:latest
ports:
- "9001:9001"
volumes:
- lhci-data:/data
environment:
LHCI_STORAGE__SQL_DIALECT: sqlite
LHCI_STORAGE__SQL_DATABASE_PATH: /data/lhci.db
LHCI_BASIC_AUTH__USERNAME: admin
LHCI_BASIC_AUTH__PASSWORD: ${LHCI_ADMIN_PASSWORD}
volumes:
lhci-data:
After startup create project and token:
lhci wizard
# Follow instructions, get BUILD_TOKEN
Slack Notifications on Degradation
LHCI doesn't send Slack notifications itself, but easy to add via CI step:
- name: Check Lighthouse results and notify
if: always()
run: |
RESULT=$(cat .lighthouseci/manifest.json | jq -r '.[0].summary.performance')
SCORE=$(echo "$RESULT * 100" | bc | cut -d. -f1)
if [ "$SCORE" -lt "80" ]; then
curl -X POST ${{ secrets.SLACK_WEBHOOK }} \
-H 'Content-Type: application/json' \
-d "{\"text\": \":warning: Lighthouse Performance score dropped to ${SCORE}/100\"}"
fi
Check Specific Audits
Beyond category scores, check specific audits:
// .lighthouserc.js
assert: {
assertions: {
'render-blocking-resources': 'error',
'unsized-images': 'error',
'no-document-write': 'warn',
'uses-webp-images': 'warn',
'prioritize-lcp-image': 'warn',
},
},
Timeframe
Basic LHCI setup in GitHub Actions with temporary-public-storage — 2–4 hours. Self-hosted LHCI server + Slack notifications + fine-tuned thresholds — 1–2 business days. Full system with parallel runs, history, baseline comparison, review integration — 3–5 business days.







