You have the spreadsheet. Two hundred rows, one per city, sitting in a tab you have reopened every quarter for a year. The campaign was never hard to imagine. It was hard to justify, because two hundred pages meant two hundred trips through design and dev. This is how that backlog becomes an afternoon, and how to do it without shipping the kind of pages Google now actively demotes.
Start with the row model, not the design
Open the spreadsheet and decide what each column has to earn. Programmatic SEO is data-driven page architecture: the template provides structure, the dataset provides the value that makes each page worth visiting. So model real difference into the table before you touch a layout.
A workable schema for "[service] in [city]" splits into three kinds of column. Key columns carry the variables that change per page and feed the URL, title, and headline: city, region, service, slug. Differentiator columns carry the substance that a generic page cannot fake: local_stat (a number specific to that market), nearest_office, case_study_url, service_radius_km, local_price_band, local_testimonial. Section-routing columns tell the template where each value lands: local_stat and service_radius_km feed the hero and proof block, nearest_office feeds the map, case_study_url feeds the proof section, local_testimonial feeds the FAQ or quote. The same shape works for "[Tool A] vs [Tool B]": tool_a, tool_b as keys, then tool_a_pricing, tool_b_pricing, feature_matrix, migration_steps, verdict_summary as the differentiators that fill the comparison table and the recommendation.
The test for the schema is simple. Strip the template away and look only at the variable cells in one row. If you cannot explain why this page differs from the next in a way a searcher would care about, the schema is too thin.
Before you generate anything, ask what this page tells a searcher that the next city's page does not. If the only honest answer is "the city name," merge rows or cut them. Ninety-percent-identical pages are the fast path to a traffic cliff, and pruning them later costs more than scoping them out now.
Learn from programs that earn at scale
The programs that work at scale share one trait: unique data on every page, not a shell with a swapped noun.
Wise runs roughly 8.5 million currency-converter pages, and programmatic pages drive about 90% of its organic traffic. Each page carries a live exchange rate, a calculator, a rate-history chart, and a fee comparison against banks. The page for EUR to USD is not the USD-to-MXN page with a find-and-replace; the numbers are genuinely different and update in real time. Zapier runs 25,000-plus integration pages, one per "[App A] to [App B]" pairing, each pulling the real triggers and actions for that specific connection. That integration database is the moat a competitor cannot copy. Zillow generates roughly 3 million property pages from live MLS feeds, and Tripadvisor's "things to do in [city]" pages are powered by real user reviews that refresh themselves. Nomad List proves you do not need a corporate budget: a solo founder built about 1,000 city pages, each backed by cost-of-living, climate, and connectivity data.
The common thread is self-updating, hard-to-replicate data per page. None of these are doorways.
Get one page right, then freeze it
Build a single page and ignore the other 199. The goal is one page the team genuinely loves: on-brand, well-structured, with every market-specific value marked as a variable instead of typed in. Hero, local proof, a map block, the offer, the FAQ.
Every hour here pays off two hundred times, and so does every shortcut. Once the layout and brand are locked, nothing downstream should touch them again. This is the step worth slowing down for.
Let the rows become pages
With the template settled, the spreadsheet stops being a backlog and becomes an input. Each row fans out into its own page, variables filled in, structure untouched. This is the part Iterant handles directly: one row becomes one page, drafted on your brand, and you approve before anything ships. Nothing publishes on its own.
The pages are not locked exports. Each stays editable, so when a city needs a different case study or a sharper headline, you fix that page and leave the rest alone. That editability is your quality valve: it is where you add the per-market detail that keeps a page off the thin-content list.
Deploy where the authority already lives
Decide where the pages live. A subfolder of your main domain lets every page inherit the authority you have already built, instead of starting a separate site from zero. Subdomains work too when you need the separation. Iterant deploys under your own domain either way.
Then internal-link the set so it reads as one organized structure, not a scatter of orphans. Build a hub: a regional or service index that links down to every page, and have each page link back up and across to a few genuinely related neighbors. Programmatic contextual links earn their keep here, because Google treats a tidy, browseable hierarchy very differently from a pile of pages parked closer to search results than to your site.
Manage indexation like part of the launch
Two hundred new URLs spend crawl budget. Submit the set in an XML sitemap that lists only canonical, indexable pages, no noindex URLs, no redirects, no stale entries. Then watch the Page indexing (coverage) report in Search Console for "Crawled, currently not indexed," which is Google's polite way of saying a page did not earn its place. Check for cannibalization too: if three city pages all chase the same query, they split their own authority.
Prune deliberately. A market that never earns impressions, or duplicates a neighbor, should be noindexed or merged. Use the noindex meta tag rather than only blocking in robots.txt, because a blocked page Google has never crawled cannot be told to drop out. A smaller set where each page earns its keep outperforms a bloated one.
The reason to take this seriously has a name. In March 2024 Google folded scaled content abuse into its spam policies: "many pages generated for the primary purpose of manipulating search rankings and not helping users," regardless of whether a human or a machine made them. Doorway abuse sits right beside it, and Google calls out by name "numerous pages targeting specific geographic areas that direct users to a single destination." In the early rollout, researchers counted hundreds of sites fully deindexed; one blog had published more than 60,000 articles in six months and was wiped from the index. If your 200 rows differ only by a swapped city name, that is the policy you are testing.
The pages had been on the someday list for a year. The blocker was never the idea. It was that every page was a project. Once it wasn't, the whole list shipped in an afternoon.
Growth lead, after launch
What actually made it work
The unlock was framing, not tooling. The team stopped treating each page as a bespoke project and started treating the campaign as one template plus a table of real differences. The template carried the brand. The table carried the substance. Production, the part that used to eat a quarter, became the cheap part.
The volume was never the achievement. Two hundred near-duplicates would have been a liability. The win was removing the per-page production tax so the team could spend its attention on making each page worth landing on. If you have a spreadsheet gathering dust, that is the move. Model the difference, perfect one page, mark what varies, manage the index, and let the rows do the rest.