Skip to main content
Lighthouse is a pipeline. A browser session drives Chrome over the DevTools Protocol, gatherers collect raw page data into artifacts, audits score individual features against those artifacts, and a report renderer turns the result into HTML.

Pipeline overview

Driver

Interfaces with Puppeteer and the Chrome DevTools Protocol (CDP) over WebSocket. Sends commands to Chrome and listens for protocol events. In the Chrome extension the same protocol is accessed via the chrome.debugger API.

Gatherers

Use the Driver to collect information about the page during load. They produce three primary outputs when you run with --gather-mode: artifacts.json, trace.json, and devtoolslog.json. Gatherers do minimal post-processing.

Computed Artifacts

Generated on demand from raw artifacts. They add additional meaning and are often shared across multiple audits. For example, NetworkRecords is derived from DevtoolsLog and reused by many audits without re-parsing the log.

Audits

Tests for a single feature, optimization, or metric. Each audit receives the artifacts it declared in requiredArtifacts, evaluates a test, and resolves to a numeric score between 0 and 1.

LHR

The Lighthouse Result object (LHR) is the structured JSON output of a run. It contains all audit results, scores, and metadata. See Understanding Results for the full schema.

Report

The report UI is created client-side from the LHR. The HTML report, JSON export, and CSV export are all generated from this single result object by ReportGenerator.

Gathering outputs

Run Lighthouse with --gather-mode to inspect the three primary gathering outputs before audits run:
FileContents
artifacts.jsonStructured output from all gatherers
trace.jsonRaw Chrome performance trace; view in DevTools Performance panel
devtoolslog.jsonAll DevTools Protocol events; primary signal for network requests and page state

Terminology

Understanding the naming used throughout Lighthouse helps when reading audit code or writing your own.
TermDefinition
CategoryA roll-up collection of audits and audit groups into a user-facing report section (e.g. Best Practices). Applies weighting and overall scoring. Examples: Accessibility, Best Practices.
Audit titleShort user-visible title for the successful audit. e.g. “All image elements have [alt] attributes.”
Audit failureTitleShort user-visible title for a failing audit. e.g. “Some image elements do not have [alt] attributes.”
Audit descriptionExplains why the user should care about the audit — not necessarily how to fix it unless no external link exists. Markdown links are supported.

Protocol details

The Chrome DevTools Protocol connection is maintained via WebSocket for the CLI. Some domains must be explicitly enable()d before they emit events. Once enabled, they flush any buffered state events.
Event binding must be set up before calling Domain.enable(). Enabling a domain first and then binding misses any events that flushed during the enable call.
// will NOT work — events flushed during enable() are missed
driver.defaultSession.sendCommand('Security.enable').then(_ => {
  driver.defaultSession.on('Security.securityStateChanged', state => { /* ... */ });
});

// WILL work — binding is synchronous, enable() flushes into the bound handler
driver.defaultSession.on('Security.securityStateChanged', state => { /* ... */ });
driver.defaultSession.sendCommand('Security.enable');

Understanding a trace

core/lib/tracehouse/trace-processor.js provides the core transformation of a raw Chrome trace into meaningful objects. Each trace event has:
  • a monotonically increasing timestamp in microseconds
  • a thread ID and process ID
  • an optional duration in microseconds
  • metadata such as event type, task name, and frame

Raw trace event

{
  'pid': 41904,          // process ID
  'tid': 1295,           // thread ID
  'ts': 1676836141,      // timestamp in microseconds
  'ph': 'X',             // trace event type
  'cat': 'toplevel',     // trace category from which this event came
  'name': 'MessageLoop::RunTask', // human-readable description
  'dur': 64,             // duration of the task in microseconds
  'args': {},            // additional data such as frame when applicable
}

Processed trace

The processed trace identifies key moments (navigation start, FCP, LCP, DOM content loaded, trace end) and calculates their times in milliseconds relative to navigation start.
{
  processEvents: [/* all trace events in the main process */],
  mainThreadEvents: [/* all trace events on the main thread */],
  timings: {
    timeOrigin: 0,                  // always 0 ms
    firstContentfulPaint: 150,      // ms after time origin
    /* other key moments */
    traceEnd: 16420,
  },
  timestamps: {
    timeOrigin: 623000000,          // microseconds, marks navigation start
    firstContentfulPaint: 623150000,
    /* other key moments */
    traceEnd: 639420000,
  },
}
You can view trace.json directly in the Chrome DevTools Performance panel to visualize all trace events across processes and threads.

Module dependency graph

The internal module dependencies of core/index.js show that runner.js orchestrates both the gather phase (via navigationGather, snapshotGather, startTimespanGather) and the audit phase (Runner.audit). The report generation step is fully separate and operates only on the serializable LHR.
cli \
      -- core/index.js ----> runner.js ----> [Gather / Audit]
clients /
For deeper reading on throttling simulation, see the Throttling documentation.

Build docs developers (and LLMs) love