Programmatic pages, sanely
Programmatic SEO — generating hundreds or thousands of pages from a template — is one of the most powerful tactics in the playbook and one of the most dangerous. Done well, it puts a directory’s worth of long-tail pages in front of real demand. Done badly, it earns a doorway-page penalty and gets deindexed overnight. The entire difference is whether each page carries unique, useful information: “{city}‘s best {service}” with identical surrounding paragraphs is a doorway, while a page that pulls in genuinely city-specific data and a distinct angle is content. The right tool for the per-page content is an assistant working from structured inputs; the right tool for safely staging hundreds of pages before they hit production is a Specter dry-run on the whole batch. Together they make programmatic SEO something you can attempt on a real site.
What you need
- Specter synced to your blog
- An AI assistant you already use
- A CSV with one row per page (the variables), and a markdown template with
{placeholder}fields and section markers - Optional: a per-row research source (Wikipedia, an API, your own product database) — the richer the data, the less doorway risk
The recipe
- Pull and prepare inputs. Run a Specter pull, then build the input CSV and the template skeleton. Column quality determines output uniqueness — don’t skimp.
- Generate. Run the generator prompt to write one draft per row to
posts/drafts/. - Run the quality gate. A separate pass samples the batch and scores it. If it flags more than ~10% as low-quality, fix the template or data and regenerate — do not push.
- Dry-run, then drip-publish. A Specter dry-run is your last check on slug uniqueness and file count. Push as drafts, then publish 20–50/day over a few weeks — never all at once.
- Manage the index. Submit your sitemap, watch coverage weekly, and prune pages that don’t index within 30 days.
The prompt
Generate from the CSV and template:
Generate one page per CSV row from the template. Substitute the literal {var}
placeholders with row values, and for each section marker write content using
ROW-SPECIFIC details so every page differs genuinely from the others. Save to
posts/drafts/{slug}.md with status: draft. Rules to avoid doorway content: never
reuse exact sentences across rows, never pad, and never invent facts — if a
number would have to be fabricated, write "[verify]" so the gate can flag it.
Skip rows with thin input data and log them. Report pages generated, rows
skipped, and [verify] placeholders inserted.
Then gate the batch before pushing:
Quality-gate this batch. Sample 30 random generated files and score each on
uniqueness (near-duplicate sentences vs. other rows), specificity (details that
wouldn't apply to any other row), factual flags (count of [verify] placeholders),
and "would I publish this under my own byline". Output a report with an overall
GREEN / YELLOW / RED verdict, the stats, and the worst 5 samples. GREEN → proceed;
YELLOW → fix the template or data and regenerate; RED → stop. Push nothing.
Cost and time
| Batch size | Tokens (gen + gate) | Cost | Wall-clock |
|---|---|---|---|
| 100 pages | ~600k + ~80k | $1.50 | 30 min |
| 500 pages | ~3M + ~120k | $7 | 2.5 hr |
| 1000 pages | ~6M + ~150k | $13 | 5 hr |
Wall-clock is dominated by review and quality-gate iteration. Don’t shortcut it.
Pitfalls
- Doorway penalty. Google’s guardrails specifically target template pages that add no per-page value. The quality gate is the single most important step — don’t skip it.
- Batch-publishing trap. Don’t push all of them live on day one. Sudden index spikes look algorithmic and invite scrutiny.
- Slug collisions. Generated slugs must be unique across the batch and against your existing archive. The dry-run flags collisions — fix before push.
Where to go next
Pair it with the date-stale refresher quarterly, since year- and price-stamped pages age fastest, and after 30 days live run the thin content auditor over just these pages to cut the bottom that never gained traction. Keep batches under a thousand and re-run the gate per batch — quality drifts as batch size grows.