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 50 pages anonymously (200 signed in) 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.

Audit-as-template

pseolint 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

Stratified sampling: by template

Pages are sampled stratified across templates (up to 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. It audits by template: pages sampled stratified across templates, 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
Pages per re-audit (Pro)
up to 500
Pro plan
$19 / month
Anon retention
24 hours
  • Template-aware SpamBrain + AEO scoring, the engine pivots the unit of analysis from URL to template. Pages are sampled stratified across templates, 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; per-template breakdown landed 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 (stratified across detected templates), 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, up to 200 pages every monitoring run, stratified across templates, cumulative coverage 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.

Sources