Background
Generating thousands of SEO pages from real structured data — without burning
budget on LLM tokens, and without producing the kind of low-quality content
that Google's OriginalContentScore and pandaDemotion
signals push down the rankings — is its own engineering problem. The
"programmatic SEO" pattern (template-rendered pages over a structured entity
universe) has been around for years; what's not commodified is doing it well
at portfolio scale, with quality gates, internal linking, and incremental
LLM enrichment driven by GSC feedback.
This case study covers the programmatic SEO pipeline Purcell Analytics built inside its own internal command center to power content engineering across the portfolio. It published 1,855 pages to this site alone, with target volumes of 5K+ across other portfolio properties.
The problem
The constraints are well-defined and conflict with each other:
- Volume needs to scale to thousands of pages — manual blog writing tops out at low hundreds before someone burns out.
- Quality has to clear the bar Google sets for Helpful Content. AI-generated bulk corpora don't, by default; they accumulate
pandaDemotionand depress site authority. - Cost has to be near zero on initial generation. Spending $0.05 per page × 5,000 pages × N portfolio sites adds up faster than any reasonable initial-launch budget allows.
- Maintenance has to be cheap. You can't redeploy 5,000 pages by hand every time the template changes.
The pattern that resolves these tensions is structured-data-first generation: real entity universes (real B2B SaaS tools, real industry/process matrices), real templates that render meaningful structured fields, quality gates that auto-noindex anything below threshold, and an LLM upgrade path reserved for pages that prove themselves in GSC traffic.
The approach: an entity → page → publish pipeline with quality gates
Entity model
The pipeline starts with EntityType records (e.g.,
integration_recipe, automation_playbook) and
ProgrammaticEntity instances under each type. Entities carry the
real structured fields that will drive page generation — for an integration
recipe, that's a tool pair, use cases, integration methods, common data flows,
complexity. For an automation playbook, it's an industry × process pair,
pain points, typical tools, automation approaches, measurable outcomes.
A per-project seed command (seed_purcell_analytics for this site;
similar commands for other portfolio properties) sources entities from real
data: a curated 235-tool B2B SaaS catalog hand-picked for buyer-intent
relevance, plus a 13-industry × 30-process matrix grounded in actual client
landscapes.
Template-first generation
generate_programmatic_pages renders each entity through a
PageTemplate with body_strategy='template'. Pre-rendered
HTML lists for use cases, integration methods, and outcomes are produced from
the structured fields — no LLM round-trip. Each generated page is a
ProgrammaticPage row keyed by URL, with the structured entity
data preserved in JSONB so frontends can render rich UI components on top of
the same data.
The output is genuine: every page has real tool combinations, real industry contexts, real pain-point and outcome lists, and a meaningful URL slug. There's no LLM invention happening at this stage, which keeps cost at zero and removes hallucination from the failure modes.
Quality gates
A 7-signal ContentQualityService scores every generated page on
body length, structural completeness, internal-link density, structured-data
richness, and other heuristics calibrated against the 2024 Google Content
Warehouse leak. Pages below the configured threshold get
status='noindex' automatically. The threshold is per-project;
PA's was 40, with the actual score distribution centering around 78 — well
above the floor.
Internal linking + hub generation
build_internal_links builds a sibling and parent-child link
graph across every page in the project, so every detail page links to its
hubs and to a few related siblings. generate_hub_pages creates
hub pages automatically for every group_key with at least two
children — categories, industries, process types — so the long tail
automatically rolls up to higher-funnel landing pages.
Multi-destination publishing
publish_programmatic_pages reads from the central pipeline DB
and UPSERTs into each destination project's programmatic_page
table. Connection details for each destination come from per-project Doppler
secrets (pa-<slug> projects), so adding a new destination is
a Doppler config plus a row in the central TrackedProject table —
no code changes.
LLM upgrade path (optional, GSC-driven)
After GSC reports impressions on specific URLs, the top performers can be
upgraded to body_strategy='hybrid' — same structured data, plus
LLM-generated narrative sections. The LLM cost stays bounded (top 5% of
pages × low per-page cost) and is justified by proven traffic. Pages that
never earn impressions stay template-only, costing nothing.
Outcomes
A few concrete numbers from this build:
- 1,855 programmatic pages live on Purcell Analytics: 1,505 integration recipes + 350 automation playbooks. Initial publish cost $0 in LLM tokens.
- Average
quality_scoreacross the corpus: 78, with a floor of 50 (every page well above the 40 noindex threshold). - Hub pages auto-generated for every category-pair and industry with two or more children — 153 hubs at first publish.
- Adding a new portfolio destination is a Doppler config + a
TrackedProjectrow. The pipeline doesn't need code changes.
The pattern generalizes. Every portfolio site that has structured-data domains to mine — recipes, playbooks, glossary, comparison tables, location pages — can run through the same pipeline with project-specific entity definitions and templates. The marginal cost of expanding is in content design, not in engineering.
The stack
The pipeline runs on Django 5.2 + Celery (in the central command center), PostgreSQL for the entity / page tables (per-project Postgres or Supabase), Anthropic and OpenAI SDKs (optional, only for LLM upgrade phase), Doppler for per-project credentials, and a small set of management commands that orchestrate the seed → generate → link → hub → quality → publish flow.
If your business has a real structured-data domain that could power buyer-intent pages at scale — and you want to avoid the trap of either manual writing or AI-bulk slop — this is exactly the kind of work we do.