← Back to Blog
Programmatic SEOSEO StrategySEOContent Strategy

Programmatic SEO After AI Overviews: Moat or Doorway

I shipped 60 industry pages and 20 persona pages programmatically. The word counts were fine and the pages still failed, for two unrelated reasons. Here is the test I use now.

SPSantosh Paudel· September 6, 2026· 12 min read
Table of contents

Programmatic SEO still works after AI Overviews, but only for pages carrying something that exists nowhere else. Word count was never the test. Google's spam policy defines doorway abuse as pages created to rank for specific, similar queries — an intent test, not a length test. I know the difference because I shipped 60 industry pages and 20 persona pages on this site. The industry pages carry between 543 and 898 unique words each, median 739, and fewer than half of them have ever recorded a single impression. The persona pages sat behind a 404 for months. Two failures, and only one of them is about page quality.

What I actually built

The generator is a Next.js route with generateStaticParams over a typed data file, one object per industry, rendered through a shared component. I wrote up the mechanics in architecting a programmatic content engine on Next.js and Supabase. The build is not the hard part. The build took a weekend. Deciding what belongs on the pages is the part I got wrong.

The industry pages: quality held, strategy did not

Sixty pages, one per industry, each with its own problem statements, its own gap analysis, its own FAQ. Nothing is a token swap. Run any near-duplicate check over them and they pass.

Across a quarter the whole /industries section drew 253 impressions and one click, spread across 26 URLs out of 60. The two pages with enough data to name a position sit at 52.7 and 65.6; my own audit note puts the programmatic set as a whole at position 40 to 100. I cannot give you a tighter band than that, because most of these pages have never generated the impressions to have a position at all — which is itself the finding.

Meanwhile my dev-build and behavioural-maths posts — the ones where I show arithmetic or paste a real Search Console row — rank between 2.8 and 15.5. Same author, same domain, same quarter. The industry pages are not thin. They are off-positioning: they say things about an industry that anyone in that industry already knows, written by someone with no first-hand claim on it. Length was never going to fix that.

The persona pages: a 404 nobody saw

Twenty persona pages lived at /for/[persona]. There was no page at /for. Every link pointing at the hub hit a 404, so the 20 children had almost no internal link equity flowing in and no browsable path from the navigation. They were, structurally, what Google's doorway definition describes: pages closer to search results than to a defined, browsable hierarchy.

That one is embarrassing because it is not a content judgement at all. It is a missing file. I found it during the audit I wrote up in 389 pages, 22 clicks, alongside 164 of 453 built pages shipping with no og:image and the site emitting a different anonymous Person entity on every single page.

Programmatic quality and programmatic strategy are separate failures

This is the part I keep seeing collapsed into one argument. "Is programmatic SEO dead?" gets answered with word counts, and word count only addresses one of the two ways these page sets fail.

  • Quality failure: the template produces near-identical pages with a city or job title swapped in. Google's scaled content abuse policy names this directly — many pages generated primarily to manipulate rankings rather than to help users.
  • Strategy failure: every page is genuinely distinct, genuinely useful, and still points at a query you have no authority to win, or sits somewhere a crawler and a human both struggle to reach.

My industry pages passed the first test and failed the second. My persona pages would have passed both if the hub had existed. Fixing the first with a longer template does nothing for the second.

The same split showed up across the rest of the site. Roughly 150 posts in the seed corpus averaged 380 words with no table, no code, no internal link and no image — a quality problem. The 60 industry pages, at roughly twice that length, were a strategy problem. I scored both sets with the model in my content pruning scoring model, but only the blog corpus got cut: published count from 267 down to 103. The industry pages were tiered by ICP overlap and left in place — thirty-four of the sixty are flagged for a future noindex or consolidation pass that has not run. That asymmetry is the point. A quality problem has an obvious remedy, so it gets one. A strategy problem sits in a document waiting for a decision.

What AI Overviews actually changed

Less than people claim, and in a direction that punishes exactly the page type above.

Google describes AI Mode as using a "query fan-out technique, breaking down your question into subtopics and issuing a multitude of queries simultaneously" (Google blog). Search Engine Land's query fan-out guide describes the same mechanism: one question turned into many related searches run behind the scenes before an answer is generated.

Two consequences follow.

The click that pays for the page may not arrive

Pew Research Center tracked 68,879 Google searches from 900 US adults in March 2025. Users clicked a traditional result on 8% of visits where an AI summary appeared, against 15% where none did, and clicked a link inside the summary on 1% of visits. Sessions ended on 26% of pages with a summary versus 16% without (Pew, July 2025).

A programmatic page whose whole business case is "rank position 4, take the click, convert" now works from a smaller click pool. A page whose business case is being the thing the answer gets built out of is affected differently. I dug into what that does to keyword targeting in the keywords that are dead to AI Overviews.

Your pages get read at the sub-query level

Fan-out means the retrieval unit is smaller than the page. A section answering one specific sub-question can be pulled even when the page as a whole does not rank for the head term. That favours pages built from many small, individually-answerable, individually-sourced blocks — the opposite shape from the 739-word narrative essay per industry I actually shipped, and a real argument for packing a programmatic page with distinct facts.

I want to be honest about the evidence here. I have no Search Console data of my own showing AI-Overview-driven behaviour, because at average position 38.8 in the US I do not have the impressions to measure it. This section is a bet on a documented mechanism. I cannot show you a result.

The moat-versus-doorway checklist

Run these seven before generating anything. Two doorway answers and I do not ship the set.

TestDoorway answerMoat answerHow I check it
Where does the per-page data come from?A variable substituted into a sentenceA source that had to be gathered, measured, or licensedDelete the shared template text — is a page still there?
Cross-page text overlapAbove ~0.6 mean 5-gram JaccardBelow ~0.3The script below, run over rendered main content
Inbound internal links per pageSitemap onlyA hub page plus contextual links from editorialCrawl the built output, count in-links per URL
Would this page exist if search did not?NoYes — someone would ask for it directlyAsk whether you would send the URL in a sales email
Who could produce page 61?Anyone holding the templateOnly someone with your data or your accessIf a competitor clones it in a day, it is a doorway
What does the visitor do next?Funnelled to one generic conversion pageA next step specific to that page's subjectDiff the CTA target across ten pages; all identical is a flag
Does each page hold a unique entity?One anonymous author blob site-wideCorrect, distinct schema per pageView source on three pages, diff the JSON-LD

My industry pages fail two of these, which is exactly my own do-not-ship threshold.

Row four catches them first. I would not have sent a hospitality operator my hospitality page, and I did not need Search Console to know that.

Row six catches them second, and this is the one I had been avoiding. The industry data file has no per-page service field at all — only the persona data file has one. All 60 ctaPrimary entries resolve to the same href: '/contact', and the page template hardcodes a single second button to /services/ai-content-systems for every industry. Sixty pages of genuinely distinct diagnosis funnel into one generic conversion page. That is the doorway shape described in Google's own definition, arrived at from the opposite direction: the content diverges and the destination does not.

So by the rule I just wrote down, I would not ship this set today. I shipped it anyway, in July, before I had the rule. The honest version of this post is that the checklist is what I built out of the wreckage.

If that checklist is producing more doorway answers than you expected on a set you have already shipped, a content audit is the cheaper next move — score what exists before generating anything else. Every fault I listed above turned up in built output I already had.

Measuring template overlap for real

Three of the seven rows automate. Rows three and seven are a crawl and a diff you can run in an afternoon: count in-links per URL in the built output, and diff the JSON-LD across three pages. Row two needs actual code, so here it is — stdlib Python, no dependencies. It computes the mean pairwise 5-gram Jaccard similarity across a set of pages: high means the pages are the same page with tokens swapped.

from itertools import combinations

def shingles(text, n=5):
    w = text.lower().split()
    return {" ".join(w[i:i + n]) for i in range(len(w) - n + 1)}

def jaccard(a, b):
    return len(a & b) / len(a | b) if (a | b) else 0.0

def template_overlap(pages, n=5):
    """pages: {slug: body_text}. Mean pairwise 5-gram Jaccard, 0.0 to 1.0."""
    s = {k: shingles(v, n) for k, v in pages.items()}
    pairs = list(combinations(s, 2))
    if not pairs:
        return 0.0
    return sum(jaccard(s[a], s[b]) for a, b in pairs) / len(pairs)

if __name__ == "__main__":
    boiler = ("we build content systems for teams that need to publish consistently "
              "every single week without hiring more writers or burning anyone out")
    token_swap = {c: f"content marketing for {c} {boiler}"
                  for c in ["dentists", "plumbers", "lawyers"]}
    distinct = {
        "dentists": "dental practices lose patients between the call and the chair " + boiler,
        "plumbers": "plumbing leads arrive at two in the morning and die in a voicemail box",
        "lawyers": "law firms cannot publish a case outcome until a partner signs off on it",
    }
    hi, lo = template_overlap(token_swap), template_overlap(distinct)
    print(f"token-swap set: {hi:.2f}   distinct set: {lo:.2f}")
    assert hi > 0.6, hi
    assert lo < 0.3, lo
    print("ok")

Output on my machine: token-swap set: 0.69 distinct set: 0.00.

Two caveats before trusting a number from it. Shared navigation and footer text inflates every score, so feed it main-content text only. And a low score proves the pages differ in wording, which says nothing about whether they differ in usefulness — my industry pages score low and still sit between positions 40 and 100.

What I would do differently

Build the hub page first, before a single child page exists. A hub that 404s costs you the entire set, and it is the failure mode that leaves no trace in any content quality metric.

Then generate ten pages and wait a quarter before generating the other fifty. On my own site, 111 of 182 ranking pages earned five or fewer impressions in a quarter — a signal that arrives just as clearly from ten pages as from sixty, at a sixth of the cleanup cost. My cleanup afterwards surfaced 32 broken internal links, 22 of them because a seed file had been committed but never run against the database. That is the real tax on generating at volume: errors scale with page count and review capacity does not.

FAQ

Is programmatic SEO against Google's guidelines?

No. Google's spam policies name doorway abuse and scaled content abuse, and both are defined by purpose — pages made primarily to rank rather than to help. Generating pages from a database is a production method, and production method is not what the policy tests.

Do AI Overviews kill programmatic SEO?

They shrink the payoff for pages whose only value is capturing a click at position 4. Pew's March 2025 data puts the click rate at 8% on searches with a summary against 15% without. Pages holding data that an answer has to cite are affected differently, and I cannot yet show you my own numbers on that.

How many words does a programmatic page need?

Wrong question, and I have the counter-example on my own site: a median of 739 unique words per industry page, and the whole set still sits at position 40 to 100. What the page needs is a fact only it has.

How do I know if my programmatic pages are doorway pages?

Delete every sentence shared with the other pages in the set. If what remains would not stand as a page on its own, you have a doorway. The Jaccard script above automates the first half of that test; the second half is a judgement call nobody can automate for you.

Are your programmatic pages a moat or a doorway? I will score the set you already have against the seven tests above and tell you which ones to keep. Book a content audit or get in touch.

Free resource

Get the AI-SEO Content Checklist

A practical checklist for getting your own content cited by Google AI Overviews, ChatGPT, and Perplexity — not just ranked.

No spam. Unsubscribe anytime.

Browse all free guides →

Run this on your own numbers

Keyword Seasonality Forecaster — free, no signup, runs in your browser.

Open the calculator →

Want to implement this with guidance?

Santosh helps founders turn insights like this into real systems.

SEO Content Strategy

External Resources

Further Reading & Tools

Related Posts

01
14 min
SEO StrategyContent Strategy
TodaySEO Strategy

Perplexity freshness and the publishing cadence maths

What is actually published about freshness in AI citations, where the two biggest datasets disagree, and the arithmetic for when refreshing an old page beats writing a new one.

Read article
02
13 min
SEOContent Strategy
TodayAnalytics & Data Marketing

Zero-Click Search ROI: My Content Payback Math

My site earned 22 clicks from 4,553 impressions in 85 days, a 0.48% CTR. I put that number through a content payback model. At my real impression yield the programme would need a 42.5% CTR to break even.

Read article
03
14 min
SEOSEO Strategy
TodayAnalytics & Data Marketing

Which Keywords Have You Already Lost to AI Overviews?

Impressions holding while CTR collapses is the AI Overview footprint. Here is the BigQuery query, a standard-library Python triage script, and what happened when I ran the same test against my own 4,553 impressions and 22 clicks.

Read article