> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/GoogleChrome/lighthouse/llms.txt
> Use this file to discover all available pages before exploring further.

# Building plugins

> Create a shareable Lighthouse plugin that adds a custom category and audits to any Lighthouse run.

A Lighthouse plugin is a Node module that implements a set of checks run by Lighthouse and displayed as a new category in the report. Plugins have a stable, semver-versioned API and are easily distributed on npm.

## Plugin vs. custom config

Before writing a plugin, decide whether you need the full flexibility of a custom config.

| Capability                                   | Plugin | Custom config |
| -------------------------------------------- | ------ | ------------- |
| Include your own custom audits               | ✅      | ✅             |
| Add a custom category                        | ✅      | ✅             |
| Easily shareable and extensible on npm       | ✅      | ❌             |
| Semver-stable API                            | ✅      | ❌             |
| Gather custom data from the page (artifacts) | ❌      | ✅             |
| Modify core categories                       | ❌      | ✅             |
| Modify `config.settings` properties          | ❌      | ✅             |

<Note>
  If you need to collect new data from the page (custom gatherers) or modify core Lighthouse categories, use a [custom config](/extend/custom-audits) instead.
</Note>

## Creating a plugin

<Steps>
  <Step title="Create package.json">
    A Lighthouse plugin is a Node module whose name starts with `lighthouse-plugin-`. Use `peerDependencies` to declare the Lighthouse version requirement — do not add Lighthouse as a direct dependency.

    ```json package.json theme={null}
    {
      "name": "lighthouse-plugin-example",
      "type": "module",
      "main": "plugin.js",
      "peerDependencies": {
        "lighthouse": "^13.0.3"
      },
      "devDependencies": {
        "lighthouse": "^13.0.3"
      }
    }
    ```
  </Step>

  <Step title="Create plugin.js">
    This is the configuration entry point for your plugin. It declares which audit files to load and defines the new category that will appear in the report.

    ```js plugin.js theme={null}
    export default {
      // Paths to your custom audit files.
      audits: [{path: 'lighthouse-plugin-example/audits/has-cat-images.js'}],

      // The new category added to the report.
      category: {
        title: 'Cats',
        description:
          'When integrated into your website effectively, cats deliver delight and bemusement.',
        auditRefs: [{id: 'has-cat-images-id', weight: 1}],
      },
    };
    ```
  </Step>

  <Step title="Write your audit files">
    Each audit is a class with a static `meta` getter and a static `audit()` method. Place audit files in a subdirectory (e.g. `audits/`) and reference them by path in `plugin.js`.

    ```js audits/has-cat-images.js theme={null}
    import {Audit} from 'lighthouse';

    class CatAudit extends Audit {
      static get meta() {
        return {
          id: 'has-cat-images-id',
          title: 'Page has at least one cat image',
          failureTitle: 'Page does not have at least one cat image',
          description:
            'Pages should have lots of cat images to keep users happy. ' +
            'Consider adding a picture of a cat to your page to improve engagement.',
          requiredArtifacts: ['ImageElements'],
        };
      }

      static audit(artifacts) {
        const images = artifacts.ImageElements;
        const catImages = images.filter(img => img.src.toLowerCase().includes('cat'));

        return {
          score: catImages.length > 0 ? 1 : 0,
          numericValue: catImages.length,
        };
      }
    }

    export default CatAudit;
    ```
  </Step>

  <Step title="Test locally">
    During development, set `NODE_PATH` to the parent of your plugin directory so that Lighthouse can resolve it as a module.

    ```bash theme={null}
    # Run from inside your plugin directory.
    # NODE_PATH=.. lets Lighthouse resolve the plugin as if it were installed in node_modules.
    NODE_PATH=.. npx lighthouse https://example.com \
      --plugins=lighthouse-plugin-example \
      --only-categories=lighthouse-plugin-example \
      --view
    ```
  </Step>

  <Step title="Publish to npm">
    Once your plugin is ready, publish it like any other npm package. Because the plugin name starts with `lighthouse-plugin-`, users can discover and install it directly.

    ```bash theme={null}
    npm publish
    ```

    Users install your plugin and then pass `--plugins=lighthouse-plugin-example` to their Lighthouse CLI invocations or programmatic API calls.
  </Step>
</Steps>

## Plugin config API

The `plugin.js` export is an object with the following top-level properties.

### `audits`

Declares the new audits the plugin adds.

**Type**: `Array<{path: string}>`

Each path should be an absolute module-style path that a consumer could pass to `require` — use the form `lighthouse-plugin-<name>/path/to/audit.js`.

### `category`

Defines the display strings and scoring for the plugin's report section.

| Property            | Type                          | Required | Description                                                                    |
| ------------------- | ----------------------------- | -------- | ------------------------------------------------------------------------------ |
| `title`             | `string`                      | Yes      | Display name in the report. Keep it short (under 20 characters).               |
| `description`       | `string`                      | No       | Explains the category's purpose. Link to docs or your repo.                    |
| `manualDescription` | `string`                      | No       | Description for manual audits only. Use only if you've added manual audits.    |
| `auditRefs`         | `Array<{id, weight, group?}>` | Yes      | Audits to include. `weight` controls their contribution to the category score. |
| `supportedModes`    | `string[]`                    | No       | Lighthouse modes this category supports. Supports all modes if omitted.        |

### `groups`

Optional. Groups allow you to visually cluster audits within a category in the HTML report.

```js theme={null}
groups: {
  'images': {
    title: 'Image audits',
    description: 'Audits related to images on the page.',
  },
  'scripts': {
    title: 'Script audits',
  },
},
```

Reference a group from `auditRefs` by setting the `group` property to the group key:

```js theme={null}
auditRefs: [
  {id: 'my-image-audit', weight: 1, group: 'images'},
  {id: 'my-script-audit', weight: 1, group: 'scripts'},
],
```

## Plugin audit API

### `meta`

A static getter returning the audit's metadata.

| Property            | Type                                                 | Required | Description                                                    |
| ------------------- | ---------------------------------------------------- | -------- | -------------------------------------------------------------- |
| `id`                | `string`                                             | Yes      | Kebab-case identifier, typically matching the filename.        |
| `title`             | `string`                                             | Yes      | Short, user-visible title when the audit passes.               |
| `failureTitle`      | `string`                                             | No       | Short, user-visible title when the audit fails.                |
| `description`       | `string`                                             | Yes      | Why the audit matters. Markdown links supported.               |
| `requiredArtifacts` | `Array<string>`                                      | Yes      | Artifacts that must be present. See available artifacts below. |
| `scoreDisplayMode`  | `"numeric" \| "binary" \| "manual" \| "informative"` | No       | How the score is displayed in the report.                      |

### `audit(artifacts, context)`

The function that computes results. Returns an object with at least a `score` property.

| Return property | Type             | Description                                                                     |
| --------------- | ---------------- | ------------------------------------------------------------------------------- |
| `score`         | `number \| null` | `0` to `1`. Use `null` with `notApplicable: true` when the audit doesn't apply. |
| `numericValue`  | `number`         | Optional raw numeric value exposed in the JSON result.                          |
| `notApplicable` | `boolean`        | Mark the audit as not applicable. Score should be `null`.                       |
| `details`       | `object`         | Structured table or list details for the report.                                |

<Tip>
  Scores above `0.9` are collapsed into the "Passed audits" section by default. Use this to signal a near-perfect result without fully passing.
</Tip>

## Available artifacts

<AccordionGroup>
  <Accordion title="Page context artifacts">
    | Artifact        | Description                                                |
    | --------------- | ---------------------------------------------------------- |
    | `fetchTime`     | ISO timestamp of when the page was fetched                 |
    | `URL`           | The requested and final URLs of the page                   |
    | `GatherContext` | The gather mode (`navigation`, `timespan`, `snapshot`)     |
    | `settings`      | The Lighthouse settings used for this run                  |
    | `Timing`        | Internal performance timings for the Lighthouse run itself |
  </Accordion>

  <Accordion title="Host environment artifacts">
    | Artifact         | Description                                      |
    | ---------------- | ------------------------------------------------ |
    | `BenchmarkIndex` | Rough estimate of host machine CPU speed         |
    | `HostFormFactor` | `'mobile'` or `'desktop'`                        |
    | `HostUserAgent`  | The user agent string of the host browser        |
    | `HostProduct`    | The Lighthouse integration (CLI, DevTools, etc.) |
  </Accordion>

  <Accordion title="Page content artifacts">
    | Artifact              | Description                                |
    | --------------------- | ------------------------------------------ |
    | `ConsoleMessages`     | Console API calls and runtime exceptions   |
    | `MainDocumentContent` | The HTML of the main document              |
    | `ImageElements`       | All `<img>` elements and their attributes  |
    | `LinkElements`        | All `<link>` elements and their attributes |
    | `MetaElements`        | All `<meta>` elements and their attributes |
    | `Scripts`             | All scripts loaded by the page             |
    | `ViewportDimensions`  | The inner width/height of the viewport     |
  </Accordion>

  <Accordion title="Network & trace artifacts">
    | Artifact      | Description                                                                                                          |
    | ------------- | -------------------------------------------------------------------------------------------------------------------- |
    | `DevtoolsLog` | All DevTools Protocol events recorded during page load. Use with `NetworkRecords` to get structured request objects. |
    | `Trace`       | Raw Chrome performance trace. Use with trace processor utilities for timing data.                                    |
  </Accordion>
</AccordionGroup>

<Note>
  Lighthouse has additional internal artifacts not on this list. Those are considered experimental and may change without notice. Only use listed artifacts if you need a stable plugin.
</Note>

## Using network requests

Network request data is derived from `DevtoolsLog` at audit time using the `NetworkRecords` computed artifact. Pass `context` to allow Lighthouse to cache the result across audits.

```js audits/header-police.js theme={null}
import {Audit, NetworkRecords} from 'lighthouse';

class HeaderPoliceAudit extends Audit {
  static get meta() {
    return {
      id: 'header-police-audit-id',
      title: 'All headers stripped of debug data',
      failureTitle: 'Headers contained debug data',
      description: 'Pages should mask debug data in production.',
      requiredArtifacts: ['DevtoolsLog'],
    };
  }

  static async audit(artifacts, context) {
    const devtoolsLog = artifacts.DevtoolsLog;
    // Pass context so Lighthouse can cache and share the parsed result.
    const requests = await NetworkRecords.request(devtoolsLog, context);

    const badRequests = requests.filter(request =>
      request.responseHeaders.some(
        header => header.name.toLowerCase() === 'x-debug-data'
      )
    );

    return {
      score: badRequests.length === 0 ? 1 : 0,
    };
  }
}

export default HeaderPoliceAudit;
```

## Naming best practices

### Category titles

Keep category titles under 20 characters — ideally a single word or acronym. Avoid prefixes like "Lighthouse" or "Plugin".

### Audit titles

Write titles in the present tense that describe what the page **is** or **is not** doing.

**Do**

* "Uses HTTPS"
* "Does not use HTTPS"
* "Tap targets are sized appropriately"

**Don't**

* "Good job on alt attributes"
* "Fix your headers"

### Audit descriptions

Provide brief context for why the audit matters and link to guides. Markdown links are supported.

**Do**

> All sites should be protected with HTTPS, even ones that don't handle sensitive data. HTTPS prevents intruders from tampering with communications. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/https).

**Don't**

> Images need alt attributes.

## Common mistakes

<Warning>
  Forgetting to filter or normalize artifact data is a frequent source of bugs.
</Warning>

* **Forgetting to filter**: Most audits have a specific use case, but edge cases come up frequently — `blob:`, `data:`, and `file:` URLs for network requests; non-JavaScript script types; 1×1 tracking pixel images.
* **Forgetting to normalize**: Artifact values represent what was observed on the page. Header names and values, script `type` values, and `src` values may have leading/trailing whitespace, be mixed-case, or be relative URLs.

## Examples

* [Lighthouse Plugin Recipe](https://github.com/GoogleChrome/lighthouse-plugin-example) — official minimal example
* [Field Performance](https://github.com/treosh/lighthouse-plugin-field-performance) — displays Chrome UX Report data
* [Publisher Ads Audits](https://github.com/googleads/pub-ads-lighthouse-plugin) — a well-structured, full-featured plugin
* [Green Web Foundation](https://github.com/thegreenwebfoundation/lighthouse-plugin-greenhouse) — checks which domains run on renewable power
