Programmatic SEO for side projects
Generating thousands of pages is the easy part and the part that gets you ignored. How to decide what deserves a page, and what to put on it.
Programmatic SEO means one template and a data set: a page per town, per product, per pair of things being compared. It works. It also fails more often than it works, and it fails in a way that takes the whole site down with it.
The failure is always the same. Someone generates 20,000 pages from a thin data set, Google indexes 400 of them, and the site never recovers its reputation.
The test before you generate anything
For each page you're about to create, ask whether a person searching that exact term would be satisfied landing on it.
Not "is this page technically unique". Uniqueness is trivial, you can swap a town name and get 400 unique pages. The question is whether the page answers the question.
"Plumbers in Croydon" with 12 real plumbers, their opening hours and their actual reviews: yes. "Plumbers in Croydon" with a heading, a stock photo and the sentence "Find the best plumbers in Croydon": no, and publishing 400 of those will cost you the 12 pages that were good.
Pick the right data shape
Three shapes work reliably.
One entity per page. A town, a product, a station, a school. Works when each entity has enough genuinely different data attached. The test is whether two pages would read differently to a human.
Comparisons. "X vs Y". These rank well because the search intent is narrow and the pages are naturally different. The trap is combinatorial explosion: 200 items gives you 19,900 pairs, and 19,800 of them are comparisons nobody wants. Generate only the pairs with real search demand.
A calculation. "Take-home pay on £45,000" with a working calculator and the actual numbers. Strong, because the page does something rather than describing something.
Set a floor and enforce it in code
This is the single thing that separates the sites that work from the graveyard.
export function shouldIndex(item: Item) {
const populated = REQUIRED.filter(f => item[f]?.length).length
return populated >= 5 && item.summary.length >= 200
}
Then in the page:
export async function generateMetadata({ params }) {
const item = await getItem((await params).slug)
return {
title: `${item.name}: ${item.oneLiner}`,
robots: shouldIndex(item) ? undefined : { index: false, follow: true },
}
}
The thin pages still exist and still get linked. They just don't ask to be ranked. Publishing 800 good pages and noindexing 4,000 thin ones beats publishing all 4,800 by a wide margin.
Release in batches
Putting 5,000 new URLs in a sitemap overnight on a 3-month-old domain looks exactly like what it is.
Ship 200, wait a fortnight, look at Search Console. If they're indexing and getting impressions, ship the next 500. If 190 of the 200 are sitting in "Crawled, currently not indexed", your template is too thin and generating 4,800 more won't fix it.
That feedback loop is the whole reason to go slowly. It tells you the template is wrong while it's still cheap to change.
Internal linking is most of the value
A generated page with no inbound links is invisible no matter how good it is. Google has to be able to walk to it.
Every page should link to its parent category, its 5 nearest neighbours (by whatever "near" means in your data), and back to a hub. Hubs link down to everything in their group.
This is also why the entity clustering matters for retrieval. When 30 pages all reference the same entity from different angles and link to each other, you're giving a much richer signal than 30 orphans would.
Do these unglamorous bits
Unique titles and meta descriptions from the data. Not a template with one word swapped. Use 2 or 3 real fields.
Schema that matches what the page actually is. Place, Product, Dataset. Never invent aggregate ratings you don't have.
A canonical on every page. Faceted filters generate URL variations, and without canonicals you'll have 8 versions of every page competing with each other.
Real dates. If you show "last updated", it has to be true. A page that claims today's date every day is a pattern that gets spotted.
The realistic timeline
New domain, 500 decent generated pages: roughly nothing for 3 months, then a slow climb. Most of the traffic arrives in months 6 to 12.
If you need traffic sooner than that, this isn't the technique. Programmatic SEO is a compounding asset with a long lead time, and the projects that succeed at it are the ones still there in month 9.