Programmatic SEO is one page template multiplied by one real dataset. We run 46 such pages on Favors.dev, and for six straight weeks they out-performed all 45 of our hand-written blog posts combined. This is the teardown, with the actual Search Console readings, including the part where we shipped an article that competed with our own templated pages and lost badly.
Almost everything written about this topic is a vendor explainer illustrated with Zillow, Nomad List and Zapier integration pages. Those are useful as proof the technique works and useless as instructions, because none of them are a company of one with no traffic and no links. So here is the version at our scale: what we built, what it did week by week, what it cost us, and what I would do differently.
What is programmatic SEO?
Programmatic SEO is the practice of generating a set of pages from a single template and a structured dataset, so that each page targets one specific long-tail query. One template, many rows, one page per row. It is often shortened to pSEO, and it is a production method rather than a separate ranking strategy: the pages still have to earn their rankings the ordinary way, by being the best available answer to the question they target.
The one-line definition
Programmatic SEO turns a dataset you maintain into a page per row, each answering one specific query that would never justify a hand-written article on its own. The dataset is the moat. The template is just the delivery mechanism.
The distinction that matters is between a dataset and a word list. If your rows differ only by a noun you drop into the same sentences, you are generating filler. If your rows differ by facts a reader would actually want (what it costs, what it requires, whether it is worth the afternoon), you are publishing a reference work that happens to have been assembled by a script.
What happened when we shipped 46 templated pages
Our property went from 511 impressions to 2,050 in six weeks, and for most of that period the templated pages, not the blog, were the reason. The dataset behind them is a verified index of places a founder can submit a startup: 46 directories, each with its submission route, whether it costs anything, whether it needs an account, its domain authority, and a date stamp for when we last confirmed it was alive.
Every row below is a real reading from our own Google Search Console property, pulled on the date shown over the preceding 28 days.
| Reading | Impressions | Clicks | Avg pos | What was happening |
|---|---|---|---|---|
| Jul 4 | 511 | 9 | 12.3 | Baseline. The directory hub sits at 102 impressions, one child page at 93 impressions and position 6.1. |
| Jul 11 | 872 | 11 | 11.9 | Up 70% in a week, almost entirely from the templated pages entering the index. |
| Jul 19 | 1,080 | 11 | 12.8 | Position dilutes as more pages enter at deeper spots. That is normal, not a decline. |
| Jul 25 | 1,120 | 10 | 12.7 | Eight ranking blog posts account for about 89 of the 1,120 impressions. |
| Aug 1 | 1,250 | 11 | 13.4 | Blog subtotal reaches about 161. The templated surface is still carrying the property. |
| Aug 8 | 1,330 | 14 | 15.6 | Blog 227 across 19 posts. Best click week to date, and 12 of the 14 clicks are not blog posts. |
| Aug 15 | 2,050 | 15 | 18.7 | Four times baseline. The blog finally surges to 844 impressions across 32 posts, 41% of the property. |
Three things in that table are worth more than the headline growth.
The child pages beat the hub, consistently. Our index page for the whole set has spent every reading around position 27 to 35, while the individual directory pages sit between positions 3 and 8. The specific page wins the specific query, and the overview page competes against every other overview page on the internet. That is the entire argument for the technique in one comparison, and it held across seven consecutive readings.
Impressions arrive long before clicks. Our clicks went 9, 11, 11, 10, 11, 14, 15 while impressions quadrupled. Long-tail pages get seen far more often than they get clicked, and if you judge the experiment on clicks in month one you will kill something that is working. Watch the number of ranking pages and the impression trend first.
Average position gets worse as this succeeds. Ours drifted from 12.3 to 18.7 while impressions quadrupled. Every new page enters the index at a deep position and drags the site-wide average with it. That number is close to meaningless during a pSEO rollout, and watching it will convince you that you are failing while you are winning.
One honest correction to the story, because the most recent reading complicates it: in the window to August 15 our blog jumped to 844 impressions across 32 ranking posts, 41% of the whole property. The editorial content did eventually compound, and it compounded harder per page than the templated set. The right conclusion is not that programmatic beats writing. It is that programmatic buys you a surface that ranks while your writing is still maturing.
What flopped, and what it cost us
We cannibalized ourselves. Three weeks after the templated pages were live, I published an editorial post targeting the same directory-listing intent the hub already served. In the next reading, the blog post was catching its target query at roughly position 76 while the hub was doing 137 impressions at position 27 on the same theme, with 40-odd child pages ranking between 3 and 8 underneath it. We had entered two runners in one race, and the slower one took the traffic that would otherwise have consolidated.
The fix is a decision, not an optimization: pick which surface owns the intent, then rewrite the other one to funnel into it rather than duplicate it. In our case the hub owns it, because it is structurally better at that job, and the post exists to explain the strategy and hand the reader off. If you take one thing from this section, take that ordering. Decide before you publish, not after you notice the split in the data.
The second thing that did not work was assuming impressions would convert on their own. Across the readings, most of our clicks landed on app profile pages, the founder directory and the homepage rather than on either the blog or the directory pages. High-impression informational pages are the top of a path, and if you do not build the next step into the template, the visit ends there. Every one of our directory pages now carries a route into the apps directory for exactly that reason.
How do you find a pSEO-shaped dataset?
Look at the data you already maintain to run your product, and ask which part of it a stranger would want. Founders reach for keyword tools here and end up generating pages about queries they have no claim to. The dataset that works is almost always something you were already collecting because your product needs it, which is why competitors cannot copy it in an afternoon.
Ours came from an internal table. We were already tracking submission directories to help members get listed, including which ones needed an account and which ones had quietly died. That table was operations infrastructure for about a year before anyone noticed it was also the best public answer to a question thousands of founders type.
| Shape | One page per... | Example | Only works if |
|---|---|---|---|
| Entity directory | One page per thing in a list you maintain | Places to submit a startup, each with rules, cost and authority | The list is genuinely hard to assemble and goes stale without you |
| Pairwise comparison | One page per A vs B combination | Tool X vs tool Y, for pairs people actually weigh against each other | You hold a real opinion on each pair, not a spec-table diff |
| Attribute filter | One page per meaningful slice of a set | Free directories, no-account directories, dofollow directories | The slice is a query people type, not a checkbox you happen to store |
| Location or segment | One page per place, industry or role | Startup communities by country, tooling by team size | The facts genuinely differ per row rather than swapping a noun |
| Computed result | One page per output of a checker or calculator | A score, a checklist or a verdict generated from real inputs | The computation is the value and cannot be copied from you |
Run any candidate through one question before you build anything: if a reader landed on a single page from this set, having never heard of you, would they be glad they did? If the honest answer is no, the set will not rank no matter how many rows it has, and the fifty hours you spend generating it are fifty hours you did not spend on the two pages that would have.
Why does most programmatic SEO get filtered?
Because most of it carries no value per page. Google's spam policies name scaled content abuse directly: generating many pages primarily to manipulate rankings rather than to help people, regardless of whether automation, a model or a person produced them. The method is not the violation. The emptiness is. Their companion guidance on creating helpful, reliable, people-first content is the standard each individual page has to clear, and it does not get easier because there are a thousand of them.
In practice, four tests separate a reference work from filler. We apply them per row, not per set.
Would this page be worth keeping if only 30 people ever read it?
Fails Fill-in-the-blank paragraphs where the only change is the noun.
Passes Facts that differ per row: cost, rules, authority, response time, a verdict.
Can a reader do something after reading it?
Fails A definition, a stock benefit list, then a signup box.
Passes The exact link, the exact requirements, and what usually goes wrong.
Is anything on the page verified, and when?
Fails Data scraped once in a batch and never touched again.
Passes A re-verification job that dates every row and drops the dead ones.
Does the page beat the obvious search result?
Fails A worse version of the thing the reader already found.
Passes Something the source itself does not publish, assembled by you.
The test that saved us was the third one. Every directory in our set carries a last-verified date, and a scheduled job re-checks the rows and removes the dead ones. Roundups rot silently: we once found a recommendation on our own blog pointing at a product whose domain had quietly become somebody's personal site, while every other directory on the internet still listed it as active. Freshness is not a ranking trick here. It is the only reason a reader should prefer your page to the source.
How do you actually build it?
A pSEO surface needs three pieces: a data source, one dynamic route, and a build step that turns every row into a static page. Ours runs on Next.js and Supabase, and the whole thing is a single route file of a few hundred lines.
The data source is a Postgres view exposing only verified, active rows, so an unverified directory cannot leak into the public index by accident. The route is /startup-launch-directories/[slug], and generateStaticParams enumerates every slug at build time so all 46 pages are prerendered rather than assembled per request. A 24-hour revalidate window means an edit to the dataset appears without a deploy. Each page emits its own metadata, breadcrumb structured data and FAQ structured data built from that row's own content.
The part worth copying is where the per-page prose comes from. It is not a template with holes. Each row carries a stored block of content generated once from the verified facts we hold about that directory (what it is, who it suits, how submission works, whether it is worth an afternoon, and half a dozen grounded questions), then re-checked when the row is re-verified. That is what makes the pages differ from each other in substance rather than in nouns, and it is the single largest determinant of whether a set like this survives.
Budget it honestly: a weekend for the route and the template, considerably longer for the dataset. The engineering is the easy half. We shipped 46 pages, and the constraint was never the code.
How should templated pages and posts link together?
Treat them as one system with two jobs: the templated pages catch the specific queries, the editorial pages explain and persuade, and each links to the other in exactly one direction per intent. Our rules, learned the expensive way:
- One surface owns each intent. If a post and a templated page target the same query, the post gets rewritten to funnel into the page. No exceptions, because the alternative is the split we measured.
- Every templated page links up and sideways. Up to the hub, sideways to two or three genuinely related rows. This is what gets deep pages crawled without a link-building campaign.
- Posts link down to specific rows, not just the hub. A named example in the middle of a paragraph passes more useful signal than a nav link, and it reads better.
- Every page has a next step. Informational traffic that lands and leaves is a vanity metric. The templated page should offer the obvious next action for somebody who just learned the thing.
If you want to see the surface this whole post is about, it is public: the startup launch directories atlas is the same 46 pages the numbers above describe. The strategy behind it is in our guide to startup launch directories, the link-value case is in directory backlinks for SaaS SEO, and the weekly rhythm that keeps any of it maintained is in SEO for solo founders. For where programmatic fits in the wider zero-budget picture, start at SaaS marketing on no budget.
Frequently asked questions
Is programmatic SEO against Google's guidelines?
No. Generating pages at scale is not itself a violation. What Google's spam policies prohibit is scaled content abuse, meaning pages produced in volume with no original value, whether a human or a model wrote them. A directory page that carries verified costs, submission rules and an honest verdict for one specific service is a useful page that happened to be built from a template. A page whose only unique element is the product name in the headline is the thing the policy is aimed at. The test is value per page, not how the page was assembled.
How many pages do you need for programmatic SEO to work?
Far fewer than the case studies suggest. Our set is 46 pages, and it took our property from 511 impressions in a 28-day window to 2,050 over six weeks. The number that matters is how many rows you can keep genuinely accurate, not how many rows you can generate. Fifty maintained pages beat five thousand abandoned ones, and fifty is a weekend of engineering for one founder once the dataset exists.
What makes a good dataset for programmatic SEO?
A good dataset has three properties: every row differs on facts a reader would care about, the set is annoying enough to assemble that nobody has published it well, and it decays without maintenance so your version stays ahead. If you can swap one noun in a paragraph and produce the next page, you do not have a dataset, you have a mail merge. Look at what you already collect to run your product. That is usually where the real one is hiding.
How long does programmatic SEO take to rank?
Faster than editorial content, in our experience. Our templated pages started registering impressions within roughly two to three weeks of going live, and several sat on page one within a month, while individual blog posts typically took four to eight weeks to surface at all. The reason is competition, not magic: long-tail queries about one specific entity have thin competition, so a genuinely useful page wins them quickly. Clicks lag impressions by a lot longer.
Can programmatic SEO hurt the rest of your site?
It can, and it did to us in one specific way. We published an editorial post targeting the same intent our templated hub already served, and the post landed around position 76 while the hub sat near 27 on the same theme. We were bidding against ourselves and the essay lost. Decide up front which surface owns which intent, then point the other one at it. The second risk is dilution: a large set of weak pages drags your site-wide average position down and gives crawlers a lot of low-value work to do.
