We Audited 20 Production pSEO Sites: Here's What Actually Fails
Twenty live programmatic-SEO and directory sites, each crawled with pseolint v0.7.5 and sampled across its URL templates. Only three scored ready. The most common gap wasn't spam, it was answer-engine invisibility.
Executive summary
The headline isn't the spam. Across 20 audited sites, the two most widespread failures were both about being cited by AI answer engines, not about tripping SpamBrain.
- 01
Only 3 of 20 sites (15%) scored ready. Eight scored caution, nine scored concerning. Median risk was 38 on a 0-100 scale (range 4–60).
- 02
80% ship no llms.txt (16/20) and 75% fail citation coverage (15/20, 157 findings), the two most common failures in the set, both AEO gaps.
- 03
Classic spam signals were real but rarer: near-duplicate clusters on 40% of sites, doorway patterns and entity-swap on 20% each.
- 04
25% block at least one AI crawlerin robots.txt (GPTBot, ClaudeBot, PerplexityBot, or Bytespider), self-inflicted removal from that engine's citation pool.
- 05
Integrity was the weakest category grade (4 sites graded F, 4 D); discoverability was strong (17 of 20 graded A). Being findable is solved; being differentiated and citable is not.
- 06
Brand did not rescue shape: major publishers and funded SaaS sites landed in concerning alongside thin directories, pseolint scores the template, not the domain.
The verdict spread
Every site gets one site-level verdict, driven by its worst template with meaningful URL coverage. Here is how the 20 distributed.
85% of audited sites carry at least caution-level risk under an authority-blind lens. That number is high on purpose: pseolint reports the shape a newer site would be judged on, before backlinks and brand are allowed to soften it.
The rules that fired most
Ranked by share of sites where the rule produced an actionable finding (should-fix or blocker), across the 48-rule engine.
| Rule | Sites | What it means |
|---|---|---|
Missing llms.txt aeo/llms-txt | 80% 16 / 20 | No /llms.txt index at the site root. Answer engines have no map to the site's citable content, lowering the odds of an accurate citation in AI Overviews, ChatGPT, or Perplexity. |
Weak citation coverage content/citation-coverage | 75% 15 / 20 | Pages assert facts with no link to a verifiable primary source: 157 findings across the corpus, the single largest finding volume. The strongest predictor of low AI-citation eligibility in the set. |
Near-duplicate clusters spam/near-duplicate | 40% 8 / 20 | Sibling pages share most of their non-boilerplate tokens. The classic templated-bulk signal SpamBrain's scaled-content-abuse policy targets. |
Duplicate / thin titles content/title-uniqueness | 30% 6 / 20 | Missing, over-short, or slot-swap titles shared across many pages, a duplicate-intent signal even when bodies differ. |
AI crawlers blocked aeo/crawler-access | 25% 5 / 20 | robots.txt disallows one or more answer-engine crawlers (GPTBot, ClaudeBot, PerplexityBot, Bytespider). Removes the site from that engine's citation pool outright. |
Doorway patterns spam/doorway-pattern | 20% 4 / 20 | Structural-similarity clusters that also trip a content-quality signal (thin body or identical meta), the third-signal gate that separates a real catalog from a doorway. |
Every site, worst-first
The full corpus, sorted by risk score. Verdicts are authority-blind, a concerninghere means the template shape carries risk signals, not that the site is penalized. An established brand can absorb a shape a new site can't.
| Site | Verdict | Risk | Classified as |
|---|---|---|---|
airbyte.com/connectors | concerning | 60 | programmatic-directory |
numbeo.com/cost-of-living | concerning | 60 | unclear |
outlookindia.com/outlook-spotlight | concerning | 60 | unclear |
equityatlas.org | concerning | 60 | unclear |
trustanalytica.org | concerning | 60 | small-marketing |
thehairpin.com | concerning | 58 | unclear |
ramp.com/spend-management | concerning | 57 | programmatic-directory |
jasper.ai/templates | concerning | 46 | unclear |
usatoday.com/money/blueprint | concerning | 45 | unclear |
zacjohnson.com | caution | 38 | programmatic-directory |
fresherslive.com | caution | 37 | programmatic-directory |
fresherslike.com | caution | 37 | programmatic-directory |
zapier.com/apps/slack/integrations | caution | 34 | unclear |
cookcraze.com | caution | 34 | programmatic-directory |
typeform.com/templates | caution | 32 | unclear |
forbes.com/advisor | caution | 30 | unclear |
newsunzip.com | ready | 20 | programmatic-directory |
g2.com/categories | ready | 16 | small-marketing |
wikibioworth.com | ready | 11 | programmatic-directory |
healthyceleb.com | caution | 4 | unclear |
Risk is a 0-100 composite; 60 is the per-category contribution cap, so several sites share it. Site classification is pseolint's own detector, unclear means the template signal was below the confidence threshold, which itself triggers conservative rule demotion.
What we'd fix first
If this corpus were one client, the priority order would follow prevalence and effort, not severity theatre.
- #1
Ship an llms.txt (quick fix, 80% miss it)
A single markdown index at the root that points answer engines at your most citable pages. Lowest-effort, highest-prevalence gap in the set.
- #2
Add one cited primary fact per template (75% fail citation coverage)
Attach a verifiable, sourced fact to the template, a price, a dated statistic, a linked reference, so each generated page anchors to something a reader (and an LLM) can trust.
- #3
Unblock the AI crawlers you meant to allow (25% block one)
Audit robots.txt for blanket
Disallow: /on GPTBot / ClaudeBot / PerplexityBot / Bytespider. Narrow to admin routes if the block was intentional. - #4
Break near-duplicate clusters before scaling (40%)
Raise cross-page lexical variance with real per-record differentiation, not synonym swaps, the structural fix that moves a template out of doorway range.
Method & reproducibility
Each site was audited with npx pseolint <url> --sample-size 25 --max-per-template 5 on pseolint v0.7.5, July 2026. Verdicts and risk come straight from the engine; aggregation is site-level (a rule counts once per site regardless of how many pages fired it). The corpus is pseolint's open calibration corpus; 12 of 32 real targets could not be fetched in a headless environment (bot walls or HTTP/2-only origins) and were excluded, so this is the crawlable subset. Two synthetic honeypot entries were also excluded. Re-run it yourself, same command, same rules, same numbers.
Frequently asked questions
- What did the benchmark actually measure?
- Each of the 20 sites was crawled live with pseolint v0.7.5 in July 2026, sampling up to 25 pages per site (stratified across the site's URL templates). pseolint scored each site on its 48-rule engine and produced a site-level verdict (ready, caution, concerning, or critical) plus a 0-100 risk number. No manual grading, the numbers below are the tool's raw output aggregated across sites.
- What was the most common failure across production pSEO sites?
- It was not spam, it was answer-engine invisibility. 80% of audited sites ship no llms.txt file, and 75% fail the citation-coverage rule (pages assert facts without citing a verifiable source). Classic spam patterns like near-duplicate content (40%) and doorway patterns (20%) were real but less prevalent than the AEO gaps.
- How many sites passed clean?
- Only 3 of 20 (15%) scored ready. 8 (40%) scored caution and 9 (45%) scored concerning. The median risk score was 38 on a 0-100 scale. Even large, authoritative publishers landed in caution or concerning, because pseolint scores page and template shape, not brand.
- Why do well-known brands score concerning?
- pseolint is authority-blind by design. It measures the static content and link graph it can see, not backlinks, domain age, or brand trust. A concerning verdict on a major publisher means the template shape carries the same risk signals Google's SpamBrain targets; an established brand can often absorb a shape a newer site cannot. That is exactly why pseolint exposes an --authority-score flag to shift the verdict ladder for your tier. Treat these verdicts as a directional, authority-blind minimum, not a claim that a site is penalized.
- Is this a representative sample of the whole web?
- No. It is a fixed, curated corpus of programmatic and directory-style sites, and it is the crawlable subset, of 32 real target URLs, 12 could not be fetched headless (bot walls or HTTP/2-only origins) and were excluded. Read the numbers as a benchmark of common pSEO shapes, not a population estimate. The corpus and method are open so anyone can reproduce or extend them.
- How do I check my own site against these rules?
- Run npx pseolint https://your-site.com. It samples your templates, runs the same 48 rules, and returns the same verdict and risk score used in this report. Add --render for JS-rendered checks and --content-effort for the AI originality signal.
Cite this benchmark
Published under CC BY 4.0, quote, excerpt, and reuse with attribution. Please link the canonical URL; we keep it updated as the corpus grows.
APA
Kam, P. (2026). We audited 20 production pSEO sites: what actually fails. Ouranos Labs. https://pseolint.dev/research/pseo-audit-benchmark-2026
Markdown link
[We Audited 20 Production pSEO Sites · pseolint](https://pseolint.dev/research/pseo-audit-benchmark-2026)
Run the same 48 rules against your own site.
Run a free auditSources
- llmstxt.org — the /llms.txt proposal — The llms.txt proposal underpins the most common gap in this benchmark, 80% of audited sites ship no such index for answer engines.
- Google Search Central — AI features and your website — Google's AI-features guidance frames why citation coverage and crawler access govern whether a page is eligible to be cited in AI surfaces.
- Google Search Central — Spam policies: scaled content abuse — The scaled-content-abuse policy is the enforcement basis for the near-duplicate and doorway-pattern findings reported here.
- Google Search Central — Spam policies: doorways — Google's doorway-pages policy defines the structural-plus-quality signal pseolint's spam/doorway-pattern rule requires before flagging.