Monitoring Performance with Lighthouse CI in GitHub Actions

Table of Contents
Big thanks to our contributors those make our blogs possible.

Our growing community of contributors bring their unique insights from around the world to power our blog. 

Introduction
Ensuring optimal performance is critical to delivering a fast, engaging user experience—and search engines reward speed with better rankings. Lighthouse CI (LHCI) brings automated performance auditing into your continuous integration pipeline, enabling you to catch regressions early and enforce performance budgets. By integrating LHCI into GitHub Actions, you can run Lighthouse tests on every pull request, track historical trends, and block merges when performance dips below your threshold. In this comprehensive guide, we’ll walk through setting up LHCI, configuring your GitHub Actions workflow, defining budgets, publishing reports, and surfacing results directly on pull requests. You’ll finish with a bulletproof system that continuously monitors and maintains your site’s performance.

1. Why Lighthouse CI in GitHub Actions?

  • Automated Regression Detection
    Every PR runs Lighthouse audits on key metrics (LCP, TBT, CLS), catching slowdowns before they reach production.
  • Performance Budgets
    Enforce thresholds for performance scores, asset sizes, and custom metrics to prevent bloat over time.
  • PR-Level Feedback
    Comment on pull requests with pass/fail status, Lighthouse scores, and actionable advice.
  • Historical Tracking
    Serve LHCI dashboards to track performance trends across commits and branches.
  • Seamless CI Integration
    GitHub Actions makes it easy to plug LHCI into your existing workflows without external servers.

2. Prerequisites

Before diving in, ensure you have:

  • Node.js (≥12) and npm installed locally for initial LHCI configuration.
  • A GitHub repository for your web project.
  • Administrative access to add GitHub Actions workflows and secrets.

3. Installing and Configuring Lighthouse CI

3.1 Install LHCI as a Dev Dependency

In your project root:

bashCopyEditnpm install --save-dev @lhci/cli

3.2 Create an lighthouserc.js Configuration

At the root of your repo, add lighthouserc.js:

jsCopyEditmodule.exports = {
  ci: {
    collect: {
      staticDistDir: './public',       // Adjust to your built output
      url: ['http://localhost:5000'],  // Local dev server URL or staging URL
      startServerCommand: 'npm run start',
      numberOfRuns: 3,
      settings: {
        chromeFlags: '--headless',
      },
    },
    assert: {
      assertions: {
        'categories:performance': ['error', { minScore: 0.9 }],
        'first-contentful-paint': ['warn', { maxNumericValue: 2000 }],
        'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
        'total-byte-weight': ['warn', { maxNumericValue: 300000 }],
      },
    },
    upload: {
      target: 'temporary-public-storage',
    },
  },
};

Key Sections

  • collect.staticDistDir: Path to your build output.
  • collect.startServerCommand: Command to spin up your app.
  • assert.assertions: Define budgets per metric (errors will fail the CI job).
  • upload.target: Choose where to publish results (see Section 6).

4. Authoring the GitHub Actions Workflow

Create .github/workflows/lighthouse-ci.yml:

yamlCopyEditname: Lighthouse CI

on:
  pull_request:
    branches: [ main, staging ]

jobs:
  lhci:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Install dependencies
        run: npm ci

      - name: Start app in background
        run: npm run start &
        env:
          CI: true

      - name: Wait for server
        uses: jakejarvis/wait-action@master
        with:
          time: '10s'

      - name: Run Lighthouse CI
        run: npx lhci autorun
        env:
          LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}

Workflow Breakdown

  1. Trigger: On pull requests to main or staging.
  2. Checkout: Pull the PR code.
  3. Install: Use npm ci for reproducible installs.
  4. Start Server: Launch your app in the background.
  5. Wait: Pause to allow the server to warm up.
  6. Run LHCI: Execute npx lhci autorun, which collects, asserts, and uploads.

5. Managing Credentials and Permissions

5.1 GitHub App Token for PR Comments

To enable LHCI to comment on PRs, create a GitHub App token:

  1. Install the Lighthouse CI GitHub App on your repo.
  2. In your repo Settings → Secrets, add:
    • LHCI_GITHUB_APP_TOKEN: The App’s private key.

5.2 Optional: Google Cloud Storage Upload

If you prefer GCS over temporary-public-storage:

  1. Create a GCS bucket and service account key with write permissions.
  2. Add secrets:
    • LHCI_GCS_BUCKET
    • LHCI_GCS_KEY (base64-encoded JSON key)
  3. Update lighthouserc.js upload section: jsCopyEditupload: { target: 'gcs', bucket: process.env.LHCI_GCS_BUCKET, key: process.env.LHCI_GCS_KEY, }

6. Publishing and Viewing Reports

6.1 Temporary Public Storage

By default, temporary-public-storage makes reports available via unique URLs printed in the CI logs. Useful for quick sharing.

6.2 Centralized Dashboard

Set up a dedicated LHCI server or use GitHub Pages:

  1. Upload target filesystem: Writes to ./.lighthouseci directory.
  2. GitHub Pages Workflow: Commit reports to the gh-pages branch: yamlCopyEdit- name: Upload to GitHub Pages uses: peaceiris/actions-gh-pages@v3 with: publish_dir: ./.lighthouseci github_token: ${{ secrets.GITHUB_TOKEN }}
  3. Access your reports at https://<org>.github.io/<repo>/.

7. Advanced Assertion Strategies

7.1 Threshold Tiers

Different budgets for PR vs. main branch:

jsCopyEditassert: {
  assertions: {
    'categories:performance': ['error', { minScore: process.env.CI === 'true' ? 0.92 : 0.85 }],
    // ...
  },
}

7.2 Custom Assertions

Assert on custom metrics or DOM elements:

jsCopyEditassertions: {
  'my-custom-metric': ['error', { maxNumericValue: 500 }],
  'categories:accessibility': ['warn', { minScore: 0.9 }],
  'link-name': ['error', { presence: true }],
},

8. Notifications and Alerts

8.1 Slack Notifications

Add a step to notify Slack on failure:

yamlCopyEdit      - name: Notify Slack on Failure
        if: failure()
        uses: 8398a7/action-slack@v3
        with:
          status: ${{ job.status }}
          fields: repo,message,commit,author
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

8.2 GitHub Checks API

LHCI auto-creates a check run with pass/fail status—visible in the PR “Checks” tab.

9. Best Practices and Troubleshooting

  • Stable Server Endpoint: Use a consistent URL (staging or static snapshot) to avoid flaky tests.
  • Increase Timeout: If your app needs extra startup time, extend the wait or add retry logic.
  • Cache Busting: Ensure builds generate deterministic asset names to avoid stale artifacts.
  • Local LHCI Testing: Run npx lhci collect && npx lhci assert locally to debug budgets before CI.

Conclusion

Integrating Lighthouse CI into GitHub Actions transforms performance from a post-launch afterthought into a first-class citizen of your development workflow. By automating Lighthouse audits on every pull request, enforcing rigorous performance budgets, and surfacing results directly in PRs, you maintain a fast, user-friendly experience and guard against regressions. This guide gave you a step-by-step blueprint—covering LHCI setup, GitHub Actions configuration, assertion strategies, report publishing, and alerting. Implement these patterns to embed performance monitoring at the heart of your CI/CD pipeline and deliver consistently speedy, high-quality web experiences.

Let's connect on TikTok

Join our newsletter to stay updated

Sydney Based Software Solutions Professional who is crafting exceptional systems and applications to solve a diverse range of problems for the past 10 years.

Share the Post

Related Posts