Fail PRs on Degraded Web Vitals with Lighthouse CI

Web development teams use Lighthouse CI (LHCI) to automate performance testing within continuous integration pipelines, ensuring code changes meet strict Core Web Vitals benchmarks before reaching production. By defining numeric thresholds for critical metrics like Largest Contentful Paint (LCP), Cumulative Layout Shift (CLS), and Total Blocking Time (TBT), teams can configure LHCI to flag regressions and automatically block pull requests (PRs) from merging through branch protection rules.

Configuring Lighthouse CI Assertions

The core mechanism for failing a pull request lies in the Lighthouse CI configuration file, typically named lighthouserc.js or lighthouserc.json. Within this file, teams define an assert preset or individual assertion rules mapped to specific metrics.

Instead of relying solely on an overall performance score, teams target specific audit keys corresponding to Core Web Vitals:

{
  "ci": {
    "assert": {
      "assertions": {
        "largest-contentful-paint": ["error", { "maxNumericValue": 2500 }],
        "cumulative-layout-shift": ["error", { "maxNumericValue": 0.1 }],
        "total-blocking-time": ["error", { "maxNumericValue": 200 }],
        "categories:performance": ["error", { "minScore": 0.9 }]
      }
    }
  }
}

By setting the severity level to "error", LHCI exits with a non-zero exit code if a build exceeds the defined maxNumericValue or drops below the minScore. Setting a rule to "warn" displays a warning message in the build log but allows the CI step to pass, making "error" the mandatory level for blocking PRs.

Running Audits in the CI Pipeline

Teams execute LHCI within their CI workflow (such as GitHub Actions, GitLab CI, or CircleCI) after building the application. A standard pipeline step involves:

  1. Building the production application assets.
  2. Starting a local or preview server to host the static or server-rendered pages.
  3. Executing the lhci autorun command.

To reduce variance and false positives caused by network jitter or temporary CPU throttling on shared CI runners, teams configure the collect block to run multiple iterations:

{
  "ci": {
    "collect": {
      "numberOfRuns": 3,
      "startServerCommand": "npm run start",
      "url": ["http://localhost:3000/"]
    }
  }
}

Lighthouse CI evaluates the aggregated or median results against the assertions, providing a more stable evaluation of whether the code changes represent a true regression.

Integrating with Git Status Checks and Branch Protection

When lhci autorun completes, it evaluates all assertions. If any assertion set to "error" fails:

  1. The Lighthouse CI process terminates with exit code 1.
  2. The CI job status transitions to "Failed."
  3. The CI platform sends a failure status back to the repository's pull request.

Engineering teams enforce this behavior by enabling branch protection rules on target branches (like main or production). By marking the Lighthouse CI workflow job as a "Required Status Check," the repository host explicitly disables the merge button until the performance checks pass.

Reporting Results Directly on the PR

To give developers immediate context on why a check failed, teams integrate an LHCI server or third-party GitHub Actions that post a comment directly to the pull request. This comment highlights exactly which Core Web Vital regressed, the measured difference between the base branch and the PR branch, and a link to the full Lighthouse report artifact to facilitate rapid debugging.