Programmatic SEO template: shared blocks vs unique page data

Learn how to split a programmatic SEO template into shared and per-page blocks, measure uniqueness, and gate thin pages before they reach Google's index.

A programmatic SEO template has two layers. The shared layer is the layout, navigation, design and calls to action, and it can be identical on every page. The per-page layer is the data points, comparison tables, maps, computed facts and reviews, and it has to carry the page on its own. When the shared layer is most of what a reader sees, the page sits close to what Google calls scaled content abuse. This post covers four things: how to split a template into blocks, how to measure how much of each rendered page is unique, which build gates keep thin pages out of the index, and when to skip a page entirely.

What are programmatic SEO pages?

They are pages generated at scale from one template plus a dataset. Each page targets a different long-tail query that follows the same pattern, such as “[app A] + [app B] integration” or “[currency] to [currency]” (Backlinko). If you want the longer overview with examples, I covered it in what programmatic SEO is and how it works.

Is programmatic SEO bad?

The method itself is allowed. Google’s spam policies target pages “generated for the primary purpose of manipulating search rankings and not helping users.” Using a template does not break that policy.

The track record is mixed, though. In September 2026 John Mueller said programmatic SEO “often leads to a site that’s either spam, borderline spam, or low quality,” and that Google’s systems may have “lost faith in your site providing good value to users based on the old pages” (Relevant Audience, from Search Engine Roundtable). He added that fixing it “tends to take time and significant effort.” The part to notice is the site-level effect. A bad template can drag down pages that were fine.

Glenn Gabe’s August 2026 spam update cases show what that looks like:

I went through the full 2026 update timeline in Is programmatic SEO dead?.

Which parts of a programmatic SEO template can be identical, and which must be unique?

Split the template into blocks and label each one shared or per-page.

BlockLayerNotes
Header, nav, footerSharedSame on every page is fine
Layout and designSharedSiege Media counts UX consistency as a strength
CTAsShared, with conditionsBacklinko recommends conditional logic so CTAs match the page’s data
Intro sentence with the entity name swapped inShared in practiceDoes not count as unique
Data table, prices, ratingsPer-pageCarries the page
Comparisons and computed factsPer-pageCarries the page
Map, chartPer-pageOnly if the underlying data differs
Reviews, UGCPer-pageOnly when they exist
Internal linksPer-pageSiege: “contextual, dynamic links related to that specific topic instead of being the same for all pages”

Backlinko’s line on the swapped-name pattern is blunt: a city name dropped into otherwise identical text is “spam, not programmatic SEO.” Google’s doorway examples describe the same thing: “pages targeted at specific regions or cities that funnel users to one page.”

What template blocks add real per-page value?

Google wrote part of this list itself. In the thin affiliation section, it says affiliate sites add value through “price, original product reviews, rigorous testing and ratings, navigation of products or categories, and product comparisons.” The sites that rank at scale follow a similar pattern:

My test for any block: delete the entity name, then ask whether a reader could still tell which page they are on. If they could not, the block belongs to the shared layer.

How much unique content does a programmatic SEO page need?

Google has not published a number. Asked whether some percentage defines duplicate content, Mueller replied: “There is no number (also how do you measure it anyway?)” (Search Engine Journal).

The percentages that circulate come from other places:

Template word counts have the same problem. Backlinko suggests 500 to 1,000+ words. Omnius points out that tool pages such as Canva’s keep text light because the tool does the work. Google’s examples talk about value and never mention length.

Keep two ideas apart here. Mueller has said duplicate content carries no negative ranking score. Scaled content abuse is a separate thing: it is a spam policy, and it can act on the whole site.

How to measure uniqueness anyway

A percentage is still useful as an internal QA signal, as long as you don’t treat it as a Google target. I’d track two numbers on the rendered main content, with nav and footer excluded:

  1. Field share. The words rendered from page-specific fields, divided by the total words in the main content.
  2. Sibling similarity. Shingle overlap between a page and its nearest siblings, for example two pages in the same category.

The second number is closer to how near-duplicate detection works in practice. Google-affiliated researchers found 64-bit simhash fingerprints with k=3 workable across 8B pages (Manku et al., 2007). Google has not said whether Search uses that method today.

function shingles(text: string, k = 5): Set<string> {
  const w = text.toLowerCase().split(/\s+/).filter(Boolean);
  const out = new Set<string>();
  for (let i = 0; i + k <= w.length; i++) out.add(w.slice(i, i + k).join(" "));
  return out;
}

function similarity(a: string, b: string): number {
  const A = shingles(a), B = shingles(b);
  let inter = 0;
  for (const s of A) if (B.has(s)) inter++;
  return inter / (A.size + B.size - inter || 1);
}

Run it in CI on a sample of rendered pages. Any pair with high similarity is worth a manual look.

How do you stop thin pages from being published when data is missing?

Put the gates in the build so a thin page never reaches production. Google’s docs support three outcomes: generate the page, noindex it, or return a 404 / don’t generate it. The thresholds are yours to set. The values below are placeholders, loosely modelled on the codex-skills checks: field completeness, enough unique attributes, and a flag on records with “>80% field overlap.”

type Decision = "publish" | "noindex" | "skip";

const MIN_FIELDS = 6;          // placeholder, tune per dataset
const MAX_SIBLING_OVERLAP = 0.8;

export function decide(record: Record<string, unknown>, siblingOverlap: number): Decision {
  const filled = Object.values(record).filter(
    (v) => v !== null && v !== "" && !(Array.isArray(v) && v.length === 0)
  ).length;

  if (filled === 0) return "skip";                       // 404, no URL, not in sitemap
  if (filled < MIN_FIELDS) return "noindex";             // useful to users, too thin to index
  if (siblingOverlap > MAX_SIBLING_OVERLAP) return "noindex";
  return "publish";
}

At block level, render a block only when its data exists. Don’t fill the gap with “No reviews yet” text:

{entry.reviews.length > 0 && <Reviews items={entry.reviews} />}
{entry.priceHistory.length >= 2 && <PriceChart data={entry.priceHistory} />}

Generate, noindex or 404?

SituationActionGoogle source
Record or filter combination has no results404, or don’t create the URLFaceted navigation docs
Page returns 200 but looks emptyFix it: Google treats it as a soft 404, which keeps getting crawledPage indexing report
Useful to visitors, too thin to ranknoindex meta tag or X-Robots-TagBlock indexing
Facet URLs you never want indexedBlock crawling in robots.txtFaceted navigation docs

Two traps to avoid. First, don’t combine noindex with a robots.txt disallow: Google never fetches the page, never sees the noindex, and the URL can still appear in results. Second, Google’s crawl budget docs say not to use noindex to save crawl budget, because the page is still requested before it is dropped. For pages with no data, skipping them is cheaper than noindexing them. There is more on this in the indexing hub.

Does AI-reworded boilerplate count as unique content for programmatic pages?

No. Google’s spam policy names “automated transformations like synonymizing, translating, or other obfuscation techniques” under scaled content abuse, and lists copied content modified “only slightly (for example, by substituting synonyms…)” under scraping. Google’s gen-AI guidance says generating “many pages without adding value for users may violate” the policy, and asks you to “manually factcheck and review all AI-generated content.”

A shingle check will show reworded intros as unique, so the build passes them. A rater reading the page will not see any new information. Gabe’s first two August cases were exactly this pattern. If the data is generic, Omnius’s advice is to fix the data. I agree: an LLM can’t add facts that aren’t in the dataset.

Programmatic SEO best practices: a review checklist

This is what I’d check before approving a template. It is also what I’d ask any programmatic SEO services vendor to show.

  1. Data source. Proprietary data is strongest, enriched or scored public data comes next, and scraped data is the weakest.
  2. Block map. Every block is labelled shared or per-page, and per-page blocks make up most of the main content.
  3. Pilot. Three to five pages built by hand before the template ships (Backlinko).
  4. Conditional blocks. No block renders without data.
  5. Gates. Every record ends in publish, noindex or skip. Empty records never get a 200.
  6. Similarity check. Sibling overlap is checked in CI.
  7. Policy check. The template is read against Google’s scaled content, doorway and thin affiliation examples, and against the helpful-content question: “Are you using extensive automation to produce content on many topics?” (Google)
  8. Staged rollout. Track indexation and cannibalization as well as pages published.

If a record can’t fill the per-page layer, don’t build the page.