noteUpdated Guide Available: For modern performance testing with Lighthouse CI Action, GitHub Actions, and Real User Monitoring, see Automated Performance Testing: Lighthouse CI, GitHub Actions & RUM.
noteThis article keeps the lower-level, programmatic approach because it is still useful when you want Lighthouse inside an existing test suite. If you are starting from scratch in 2026, Lighthouse CI is usually the better default.
Lighthouse audits are still useful. What changed is the default way teams automate them.
Today, I would point most teams to Lighthouse CI first. This article stays around for a different reason: sometimes you want the lower-level route, with your own assertions, your own test runner, and your own wiring.
If that is the job, using Lighthouse programmatically with Mocha, Chai, and chrome-launcher still works.
For those who are new to the tooling, there are four common ways to run Lighthouse:
via Chrome dev tools
Command-line
NPM module (which is the route we are taking here)
Prerequisites: Installing Dependencies
To programmatically perform lighthouse audits, we can use the lighthouse npm package(opens in new tab), mocha(opens in new tab), and chai(opens in new tab) for writing our tests and chrome-launcher(opens in new tab) for running our lighthouse tests.
First, let’s install the above packages as dev dependencies in our project :
npm install lighthouse chrome-launcher chai mocha --save-devSetting Up Lighthouse Programmatically
Now, let’s create a file named lighthouse.tests.js in our tests directory. We’ll run our lighthouse audits through this file. Here, we’ll import the lighthouse module and chrome-launcher that helps us to open our webpage from the local development server and run the audits to test against a minimum threshold that we want our lighthouse scores to be.
While this might sound a lot to do, it isn’t much. Here’s what it looks like on actual code :
const lighthouse = require("lighthouse");
const chromeLauncher = require("chrome-launcher");
function launchChromeAndRunLighthouse(url, opts, conf = null) {
return chromeLauncher
.launch({ chromeFlags: opts.chromeFlags })
.then((chrome) => {
opts.port = chrome.port;
return lighthouse(url, opts, conf).then((res) =>
chrome.kill().then(() => res.lhr)
);
});
}And it is as simple as that. We launch the chrome browser instance with the chromeLauncher.launch method and then run lighthouse tests with the site URL and configuration for our audits. After that, we close/kill the chrome instance and return the results. And this is how it looks like when in use :
launchChromeAndRunLighthouse(testUrl, opts, config).then((res) => {
// Results are available in `res`
});Writing the Audit Tests with Mocha and Chai
So now, we can put this call inside our before hook for the tests and then have tests for each metric, something like this :
describe("Lighthouse Audits", function () {
// Timeout doesn't need to be same. It can be more or less depending on your project.
this.timeout(50000);
let results;
before("run test", (done) => {
launchChromeAndRunLighthouse(testUrl, opts, config).then((res) => {
// Extract the results you need for your assertions.
done();
});
});
it("performance test", (done) => {
// test your performance score against the threshold
done();
});
// Some more tests..
});Still looks weird? Don’t worry! Check out this repository for an example setup of lighthouse tests with mocha(opens in new tab) and try that out with your web application!
This method can be applied to automate the tests in continuous integration/deployment environments so that you don’t have to worry about manually auditing your web application and checking whether it meets the minimum satisfactory levels.
Conclusion
Use this approach when you want Lighthouse wired into an existing test suite and you need custom assertions at code level.
If you just want dependable pre-merge checks with less plumbing, the modern follow-up is Automated Performance Testing: Lighthouse CI, GitHub Actions & RUM.
bonusFor more Web Vitals work, continue with:





