Audit rules
lumen’s audit engine ships 18 built-in rules across meta, content, links, technical, performance, accessibility and social categories. Rules are small, evidence-first, and plugin-shaped — the audit engine accepts additional rules via the plugin registry.
Severity model
Three severities, no vibes:
| Severity | Weight | Meaning |
|---|---|---|
| error | 10 | wrong or broken for search |
| warning | 3 | likely costing you something |
| info | 0 | worth knowing, not a failure |
failThreshold (in lumen.config.json) picks the lowest severity that fails the run — error by default.
Scoring
Per-page score = 100 minus the weight of that page’s issues, floored at 0. Report score = the mean over audited pages. A site where nothing was actually audited scores 0 — honest, not generous.
The 18 rules
| Rule id | Default | Categories | Fires when |
|---|---|---|---|
title-missing | error | meta | no <title> or empty after trim |
title-length | warning | meta | title longer than 65 or shorter than 15 characters |
description-missing | error | meta | no meta description or empty |
description-length | warning | meta | description longer than 165 or shorter than 50 characters |
h1-missing | error | content | zero <h1> elements |
h1-multiple | info | content | more than one <h1> |
canonical-present | info | meta | no <link rel="canonical"> (multiple canonicals raise to warning) |
lang-attr | warning | content | <html lang> missing or not a plausible BCP-47 primary tag |
viewport-meta | warning | technical | no <meta name="viewport"> |
image-alt-coverage | warning | content, accessibility | any <img> without an alt attribute (alt="" counts as present) |
broken-internal-link | error | links | same-host link target fetched during the crawl returned status >= 400 |
redirect-chain | warning | links, technical | page needed two or more redirect hops to resolve |
robots-noindex | info | meta, technical | noindex via meta robots or X-Robots-Tag header |
status-error | error | technical | fetched page status >= 400 |
insecure-http | warning | technical | page served over plain http: |
mixed-content | error | technical | http: subresources on an https: page |
response-latency | warning | performance | measured response time above the threshold (default 1500 ms) |
og-tags-missing | info | social | any of og:title / og:description / og:image absent |
Length thresholds (title, description) and the latency threshold are configurable; everything else is fixed behavior. Crawl rules (broken-internal-link, redirect-chain) only fire on evidence gathered during the crawl itself — a link target that was never fetched is reported as unknown, not invented.
Overrides
Per-rule severity overrides live in severityOverrides in lumen.config.json. An unknown rule id is a config error listing the valid ids — see configuration.
Issue + incomplete reports
An Issue looks like this (evidence snippets are escaped):
{
"ruleId": "title-length",
"severity": "warning",
"message": "title is 72 characters (max 65)",
"evidence": { "selector": "head > title", "snippet": "<title>Acme Garden Tools — hand-forged broadf…</title>" },
"fixHint": "shorten the title to 65 characters or fewer"
}Interrupted runs are labeled rather than dressed up as finished:
{
"id": "example-2026-08-29t10-31-04z",
"incomplete": true,
"summary": { "pagesAudited": 37, "pagesSkipped": 3 },
"stopReason": "time_budget"
}