Configuration

lumen works with zero configuration. lumen.config.json in your project root (or the path in LUMEN_CONFIG) is for when you want to tune budgets, swap providers, or move the failure line.

The file

{
  "providers": {
    "keywords": "wikipedia-demand",
    "serp": "ddg-serp"
  },
  "severityOverrides": {
    "og-tags-missing": "warning"
  },
  "crawl": {
    "maxPages": 250,
    "maxDepth": 4,
    "maxDurationMs": 600000,
    "maxConcurrency": 5,
    "perHostMinDelayMs": 500,
    "allowPrivateHosts": ["staging.internal", "10.0.0.0/8"]
  },
  "failThreshold": "warning",
  "byok": {
    "pagespeed": "LUMEN_PSI_KEY",
    "crux": "LUMEN_CRUX_KEY",
    "openpagerank": "LUMEN_OPR_KEY"
  },
  "plugins": []
}

A missing file means full defaults. A malformed file, a non-object root, or an unknown key at a closed-vocabulary level is a ConfigError that lists the valid keys — lumen would rather refuse than guess what you meant.

Keys

KeyWhat it controls
providersprovider name per boundary (keywords, serp, pagespeed, crux, authority); unknown names are a config error listing the options
severityOverridesper-rule severity overrides by rule id
crawlbudgets: maxPages, maxDepth, maxDurationMs, maxConcurrency, perHostMinDelayMs; plus allowPrivateHosts (E1.1 local-target opt-in)
failThresholdlowest severity that fails a run: error | warning | info | off (default error)
byokenv-var NAMES for provider keys (values never enter the file)
pluginslocal plugin files implementing extra audit rules (Node-only)
historylocal history retention: maxGenerations (default 2 — current + one rotated)

Auditing local and preview targets

crawl.allowPrivateHosts lists the exact hostnames or CIDR ranges (IPv4 like 10.0.0.0/8, IPv6 like fd00::/8) the SSRF guard may reach. Listing entries here opts those ranges in BY ITSELF; --allow-private additionally opens loopback — always only at the audited URL's own origin: redirects or links to any other private host are still refused.0.0.0.0/0 and ::/0 are rejected outright as allow-everything. Prefer CIDR or IP entries: a hostname entry trusts whatever that name resolves to at call time. The flag alone covers loopback only (localhost, 127.0.0.0/8,::1); on a loopback seed the per-host politeness delay defaults to 0 because you own that server, and reports label the run target.scope: "private" so results are never mistaken for production. Pair the flag with --canonical-origin https://prod.example so scheme rules (plain-http) judge the production origin, not the preview. Note that with provider keys configured, lumen report still hands the local URL to PSI/CrUX as a query parameter (they cannot fetch it; their own fetchers stay strict) — skip those legs if that disclosure matters to you.

Crawl defaults

BudgetDefaultNote
maxPages100hard-clamped at 10,000
maxDepth5link depth from the seed
maxDurationMs300,000wall-clock stop; the report is marked incomplete
maxConcurrency5global in-flight cap
perHostMinDelayMs250per-host politeness floor

Error behavior

  • Unknown config keys fail loudly with the list of valid keys — at any closed-vocabulary level.
  • Boundary inputs have defined behavior: non-http(s) URLs are rejected, oversized pages and sitemaps are capped and skipped with a reason, malformed robots.txt falls back to the conservative default, IDN hostnames are normalized.
  • Provider failures are typed and carry the provider name, after bounded retries with exponential backoff and jitter (Retry-After honored).
  • Interrupted runs produce a report labeled incomplete: true with a stop reason, safe to re-run without duplicated side effects.
  • Plugins are Node-only — dynamically loaded local rule files; they never load in the Worker.

Fetch safety & etiquette

All fetching goes through one guarded layer: http/https only, private / loopback / link-local targets refused, re-validated after every redirect hop, per-request timeouts. On the crawl side, robots.txt is respected by default (with a documented override if you own the site and insist), the User-Agent identifies lumen with a contact URL, sitemaps feed discovery, and each host is rate-limited. Treat other people’s servers the way you’d want your logs to look.

For provider keys and what each one sends, see providers & BYOK. For the rules all this feeds, see the rules reference.