Catch the patterns that get programmatic-SEO sites deindexed — before SpamBrain does.

pseolint is the open-source linter for programmatic SEO. Paste a URL or drop it in CI: it finds the doorway clusters, near-duplicates, and thin templates that trip SpamBrain, then tells you which template to fix — one fix, N pages. It also flags which pages can get cited in ChatGPT, Perplexity, and Google AI Overviews.

We fetch up to ~500 pages over a few minutes — if it's your site and it's cache-cold, warm it first.

No signup · 3 audits/day50 pages per audit24h retention (anon)See all limits

Analytics-safe — audit runs won't touch your GA, PostHog, Mixpanel, or session-replay dashboards.

airport-hotels.exampledemo
100Risk score
Errors0
Warnings0
Info0
Clean0
Pages0 / 200 · 0.0s
scanning…

↑ Each tile = one page. Color = worst rule that fires on that page. Watch the identity mark in the nav.

Who it's for

pSEO builders

City × service grids, directories, state × fee matrices — content generated from a template at scale.

Template-site operators

Thousands of pages from one template. One structural fix should cover all of them — pseolint tells you which.

Agencies shipping client sites

Gate every client build before it goes live. Catch the deindexing risk in the PR, not in a ranking drop.

Indie SaaS with scaled pages

Integration, comparison, and feature pages that quietly drifted into doorway territory while you shipped.

v0.6 — audit-as-template

v0.6 audits your site by template. Here's what that looks like.

Pinpoint which template is broken. Fix one template, fix N pages.

This is the site verdict. siteVerdictFromTemplates picks the worst template with ≥5% URL coverage. /listing/:slug covers 97.3% of the site — so its concerning verdict drives the headline, even though /article/:slug is clean. One template-level fix, not 8,201 page-by-page investigations.

Sampling model — before & after

v0.5 — flat random sample

200 URLs drawn across the whole site. On an 8,200-URL directory, 0.2% coverage. The /listing/*template's thin-content crisis averages out with the clean article pages. Site scores caution — the problem is invisible.

200 URLs, 1 pool

v0.6 — K=10 per template

3 templates × 10 samples = 30 fetches (vs 200). Each template gets its own verdict. The /listing/* cluster surfaces an 8/10 thin-content fire rate — unmistakable. /article/* gets credit for being clean.

/listing/:slug
/category/:slug
/article/:slug

Scope

What pseolint is — and isn't.

Self-select before you run it. The audit is narrow on purpose; if you want a 360° SEO crawl, the right tool is somewhere else on this page.

What pseolint is

An audit specifically for programmatic-SEO sites (template-driven content at scale) and AI Overview readiness. v0.6 audits by template — K=10 URLs sampled per template, one verdict per template, site verdict = worst template above 5% coverage. Catches SpamBrain-classifier triggers from the March 27, 2026 core update, the May 7, 2024 site-reputation-abuse policy, the March 5, 2024 scaled-content-abuse update, and the AEO patterns that determine whether ChatGPT, Perplexity, and Google AI Overviews cite your pages.

Use it when

  • — You run a programmatic SEO site (city × service grids, state × LLC fees, app × integration matrices)
  • — You want to know which template is dragging your site score down
  • — You're worried about a Helpful Content System / scaled-content-abuse hit
  • — You want your pages cited in AI Overviews / Perplexity / ChatGPT search
  • — You want a CI gate that fails the build when a template degrades

What pseolint isn't

A general SEO audit. We don't measure Core Web Vitals, broken links, competitor research, keyword research, or backlink audits. If that's what you need, run one of these instead:

Three archetypes

Three shapes of pSEO, three shapes of risk.

Illustrative archetypes, not real sites — the shapes pseolint actually finds. Each grid shows a dominant template's sample; lower score = safer. The verifiable version is your own scan and the public leaderboard.

87Risk score5 of 40 clean

airport-hotels.example

Doorway garden

240k pages across /hotel-[city] templates. 94% of pages scored below 30 on uniqueness. SpamBrain treats these as a single thin cluster — one structural fix, not 240,000.

62Risk score15 of 40 clean

legal-directory.example

AI-generated, no receipts

Structural hygiene is fine. Every article is credible prose. Zero citations, zero bylines — signals SpamBrain increasingly uses to distinguish generation from reporting.

34Risk score26 of 40 clean

recipe-programmatic.example

Clean run

180 category pages with genuine variation in ingredient lists, prep time, first-person intros. Templates exist, but each page has a human-sized reason to exist. Rare.

By the numbers

The audit, in measurable terms.

Specific values you can cite — what we run, what we cap, and which Google policies the ruleset maps to.

Median audit time
1 minute
K per template (Pro)
10 URLs
Pro plan
$19 / month
Anon retention
24 hours
  • Template-aware SpamBrain + AEO scoring (v0.6) — v0.6 pivots the unit of analysis from URL to template. K=10 URLs sampled per template, one verdict per template, site verdict = worst template with ≥5% coverage. Programmatic-directories, blogs, ecommerce, docs, and small-marketing sites remain weighted differently. Classification-driven scoring shipped in v0.4.3; v0.5 added change-driven monitoring; v0.5.1 added links/host-section-divergence; v0.5.2 added 4 content-quality rules; v0.6 added per-template breakdown across the full ruleset (live list).
  • Engineering rigor, not marketing. Doorway-pattern findings cluster by template (one line per template group, not per-pair noise). --sample-seed makes verdicts reproducible across runs. Info-severity findings can't accumulate past a per-bucket cap. The open-source calibration corpus + runner + regression tests guard against engine drift on each release. Full engineering log at /methodology.
  • Free tier: up to 200 pages per audit (templates detected, K=10 per template), 3 audits per browser session per day, reports retained 24 hours for anonymous runs and 30 days once you sign in.
  • Pro tier: $19 per month for per-domain template-aware monitoring — K=10 per template every monitoring run, cumulative coverage across all templates grows over time, 50 audits per day and unlimited trend history.
  • Detection maps to current Google policy, leading with what hit pSEO most recently: the March 27, 2026 core update that tightened scaled-content signals on date-stacked corpora, the May 7, 2024 site-reputation-abuse policy that closed the parasite-SEO loophole (now enforced by links/host-section-divergence), the March 5, 2024 scaled-content-abuse update, and the 2022 SpamBrain rebuild that moved enforcement from manual review to silent classifier-time suppression.
  • Crawler defaults: a hard 50 MB bandwidth cap per audit, 5 parallel fetches, full robots.txt respect including Crawl-delay capped at 2 minutes.
  • Open source: MIT-licensed at github.com/ouranos-labs/pseolint, with the core engine, CLI, GitHub Action, and MCP server published as separate packages on January 15, 2026.
  • SLA targets: 99.9% hosted-audit availability, deduped responses for repeat URLs in under 5 minutes, and any forced re-crawl held to a 5 minutes minimum spacing.
  • Default thresholds: thin-content fires below 300 words, near-duplicate fires above 85% SimHash similarity, and boilerplate-ratio flags pages with over 60% shared template text.

Ship it in CI

Gate the build before a template ships broken.

Drop this into .github/workflows/pseolint.yml. It audits your build output on every PR, posts a SpamBrain Risk Score summary as a comment, and fails the check when the score crosses your threshold. Two minutes to wire up.

Prefer the CLI? npx pseolint ./out --ci-threshold concerning --format json does the same thing locally — see the MCP server for editor + agent setups.

.github/workflows/pseolint.yml
name: pSEO Lint
on: [pull_request]

jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - run: npm run build
      - uses: ouranos-labs/pseolint@action-v1
        with:
          source: ./out
          threshold: 40

FAQ

Straight answers.

What does pseolint actually check?
pseolint runs rules across 8 categories over your site as a graph, not page by page: SpamBrain spam patterns (doorway clusters, near-duplicates, entity-swap templates, thin content), content quality (titles, headings, alt text, E-E-A-T signals), internal-link structure, technical indexing (canonicals, robots, sitemaps, hreflang), and AEO — whether ChatGPT, Perplexity, and Google AI Overviews can cite your pages. Every rule maps to a documented Google policy and ships with a fix. The full, current list lives at /rules.
How is this different from Ahrefs or Screaming Frog?
Those tools were built for editorially-curated sites and check pages one at a time — they're excellent at backlinks, Core Web Vitals, broken links, and keyword research, none of which pseolint does. The SpamBrain risks of programmatic SEO live between pages: doorway clusters, near-duplicate templates, and entity-swap doorways across thousands of URLs. Per-page rules can't see them. pseolint audits the link graph and groups findings by template, so fixing one template fixes every page it generates.
What is the SpamBrain Risk Score?
A 0–100 number where lower is safer. It aggregates every rule's findings into a per-template verdict — ready, caution, or concerning — and the site score is driven by the worst template with at least 5% URL coverage, so a clean section can't hide a broken one. The score is calibrated against a curated corpus of reputable, in-production pSEO sites and is reproducible at a fixed sample seed. Full methodology lives at /methodology.
How do I gate it in CI/CD?
pseolint ships as a GitHub Action and a CLI. Point it at your build output or a preview URL, set a threshold, and the run fails the build when a template degrades past your bar. JSON output plugs into any pipeline, and the Action posts a score summary as a PR comment. A copy-paste workflow is right above this section.
What does it cost?
The audit is free — no signup for anonymous single-URL scans, with higher limits once you sign in. Pro is $19/month for per-domain monitoring: scheduled re-audits, cumulative template coverage over time, AI triage, Google Search Console integration, and rule overrides. No credit card to start. See /pricing for the breakdown.

Early-stage and built in the open. Open-source (MIT), launched January 2026, with rules across 8 categories mapped to current Google policy. We run pseolint on pseolint.dev itself and publish the result on the public leaderboard — verdict Ready, origin handled the crawl at a 106ms median TTFB, and the audit's open findings are literally our own SEO to-do list. The traction is the receipts, not a number we made up.

One URL. 60 seconds. A per-template verdict you can ship.

Audit my site — freeFree, no signup. Pro is $19/mo what's included.