How to Add Lighthouse to Your CI/CD Pipeline
Automate Lighthouse performance testing in GitHub Actions, GitLab CI, or CircleCI to catch regressions before they reach production.
Running Lighthouse manually before every deploy is error-prone — people forget, rush, or skip it under deadline pressure. Automating Lighthouse in CI catches performance regressions before they reach production, not after users notice the site slowed down.
The Options
Lighthouse CI (LHCI) — The official Lighthouse integration for CI systems. Open source, maintained by Google Chrome team. Runs Lighthouse, compares to a baseline, fails the build if thresholds aren’t met.
Unlighthouse — A site-wide Lighthouse scanner. Good for scanning many pages at once, but less suitable for per-commit checks.
Custom Lighthouse CLI script — Run lighthouse directly and parse the output. Most flexible, but more setup.
We’ll focus on Lighthouse CI since it’s the best maintained and most feature-complete option.
Setting Up Lighthouse CI
Install
npm install --save-dev @lhci/cli
Configure
Create .lighthouserc.js in your project root:
module.exports = {
ci: {
collect: {
// URL(s) to test — use your staging URL
url: ['http://localhost:3000/', 'http://localhost:3000/blog'],
// Number of Lighthouse runs to average
numberOfRuns: 3,
// Start your dev server before collecting
startServerCommand: 'npm run start',
},
assert: {
preset: 'lighthouse:recommended',
assertions: {
'categories:performance': ['error', { minScore: 0.7 }],
'first-contentful-paint': ['warn', { maxNumericValue: 2000 }],
'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
'total-blocking-time': ['warn', { maxNumericValue: 300 }],
// Disable audits that don't apply
'uses-http2': 'off',
},
},
upload: {
target: 'temporary-public-storage', // Free storage provided by LHCI team
},
},
};
GitHub Actions Integration
# .github/workflows/lighthouse.yml
name: Lighthouse CI
on:
pull_request:
branches: [main]
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/cli
lhci autorun
env:
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
The LHCI_GITHUB_APP_TOKEN is optional but enables Lighthouse CI to post results as a PR status check with a link to the full report.
Against a Live URL (Staging)
If you can’t start a local server in CI, test against your staging URL:
module.exports = {
ci: {
collect: {
url: ['https://staging.yoursite.com/'],
numberOfRuns: 3,
},
// ...
},
};
This is simpler but requires your staging environment to be accessible.
GitLab CI Integration
# .gitlab-ci.yml
lighthouse:
image: node:20
stage: test
script:
- npm ci
- npm run build
- npm install -g @lhci/cli
- lhci autorun
only:
- merge_requests
Handling Score Variance
Lighthouse scores vary between runs (typically ±5–10 points). To reduce noise:
- Set
numberOfRuns: 3(or 5 for more stability) — LHCI averages the results - Set thresholds conservatively based on your performance budgets — don’t fail at 90 if your target is 75
- Use
maxNumericValueon specific metrics rather than overall score when possible (metrics are more stable than the aggregate score)
What to Fail vs. Warn On
For a broader look at automating performance checks beyond Lighthouse, see how to automate speed testing. Not everything should fail the build:
Fail on:
- LCP over 4s (definitely a regression)
- CLS over 0.25
- Performance score drop below 60 (see what counts as a good score)
Warn on:
- Performance score below 70 (investigate but don’t block)
- FCP over 2s
- TBT over 500ms
Be conservative with failures — too many false positives train engineers to ignore or disable the check.
Combining CI and Manual Testing
Lighthouse CI catches regressions relative to your baseline. For deeper diagnostics — waterfall, CrUX field data, video recording — run debugutils.dev manually on your staging URL before deploying.
The combination of CI automation (to catch regressions) and manual diagnostic testing (to investigate issues) gives you the best of both worlds. For a structured manual approach, use our pre-deploy performance checklist.