"Programmatic SEO" sounds like a growth hack: generate thousands of pages from a database and watch the traffic roll in. It can work. It can also get a whole site treated as spam.
The short answer: using an AI coding agent, we built, checked and shipped 808 make, model and state pages in one day for a small classic-car marketplace we run. Then we cut its sitemap from about 59,000 URLs to 10,552. The result so far: it's too early to tell. Search Console shows 3 clicks from 63 impressions for the whole site from Oct 28 to Nov 2, and the new pages hadn't had a recorded visit as of Nov 1.
We run AI automation on our own businesses and publish what works, with real numbers. This post covers how we built the pages, the rules we used to keep them from becoming thin-content spam, and exactly what has happened since launch. We'll publish the 30-day results whether they're good or bad.
The business and the opportunity
The marketplace lists collector and enthusiast cars for sale. At build time it had 5,523 live listings. Every listing already had its own page, but there was nothing between "the homepage" and "one specific car."
That's a gap, because a lot of buyers don't search for one listing. They search for things like "[make] [model] for sale" or "[make] for sale in [state]." Those are category pages, and the marketplace didn't have any.
Search Console confirmed how little the site was getting from Google. In the six days of Oct 23–28 it had 0 clicks from 41 impressions.
Step 1: Decide which pages deserve to exist
This is where most programmatic SEO goes wrong. If you have 5,000 listings, you can generate a page for every make × model × city combination and end up with hundreds of thousands of pages, most showing one car or none. Google calls that thin content, and it can drag the whole site down.

Pages shipped in the build.
So before building anything, we set a minimum-inventory rule for every page type. A page is only created if there are enough real, live cars to make it useful:
| Page type | Example pattern | Minimum live listings | Pages created |
|---|---|---|---|
| Hub | "Cars for sale" | n/a | 1 |
| Make | "[Make] for sale" | 5 | 28 |
| Make + model | "[Make] [Model] for sale" | 5 | 130 |
| State | "Classic cars for sale in [State]" | 10 | 25 |
| Make + state | "[Make] for sale in [State]" | 5 | 177 |
| Make + model + state | "[Make] [Model] for sale in [State]" | 3 | 459 |
That came to 820 pages on the first pass. Any URL for a combination below the threshold returns a 404 with noindex, so if inventory drops, the page drops out of Google instead of sitting there empty.
Why no city pages? Location on this site is a free-text field, with no separate city, state or ZIP columns. When we parsed it, 97.6% of live listings mapped cleanly to a US state, but city data was too messy to trust. So we built state pages only. It's better to ship fewer pages that are accurate than more pages that are wrong.
Step 2: Make each page actually different
Two hundred pages that differ only by the word "Ohio" won't rank. Each generated page got:
- A unique title, meta description and canonical URL
- One H1 matching the search pattern
- Real listing data: the live cars in that category, plus summary stats built from actual inventory, such as a median price
- A "recently sold" block, showing confirmed sales only
- Structured data: Breadcrumb and ItemList JSON-LD, plus Open Graph tags for sharing
We didn't change the database schema. Everything is built from data the marketplace already had.
Step 3: Check it the way Google sees it
After publishing (about 12:15 PM PT), we fetched pages with a Googlebot user agent and checked each one returned a 200 with its own title, description, canonical, a single H1, Open Graph tags and valid structured data.
About 15 minutes later we shipped a second version that:
- Removed duplicate pages (820 → 808).
- Excluded prices under $1,000 from the stats, so they couldn't skew the medians.
- Rounded medians to whole dollars.
- Limited the "recently sold" block to confirmed sales only.
Then we rebuilt the sitemap as a sitemap index with a dedicated file for the new pages and resubmitted it in Search Console.
Lesson: budget for a "v2" on launch day. Generated pages look fine in a spreadsheet. The problems show up when you open twenty of them in a browser.
Step 4: Clean the sitemap
While checking the sitemap, we found a bigger problem than missing category pages. The listing sitemaps contained about 58,000 car URLs, but only about 5,500 cars were live. Most of the sitemap was sold or removed listings.

Sitemap size, before and after.
That matters because a sitemap tells Google "these pages are important, please crawl them." Pointing Google at tens of thousands of dead or near-dead pages wastes crawl attention that should go to your best pages.
On Nov 1 we cleaned it up:
- Sitemap went from about 59,000 URLs to 10,552: 595 general pages, 789 for-sale category pages and 9,168 listing pages. The second listing sitemap was removed entirely.
- Resubmitted in Search Console.
Step 5: Link to the new pages
A page Google can't reach through links is a page Google won't value much, sitemap or not. After the launch, the new pages had zero visits, partly because nothing on the site linked to them. On Nov 1 we added:
- Homepage links to the hub, 12 top makes and 10 states
- Links from every listing page to its make, model and state pages
- Links from the site's buying guides to the for-sale pages
Results so far (honest version)
As of Nov 4, the latest Search Console data runs through Nov 2:
- Oct 23–28: 0 clicks, 41 impressions for the whole site (before launch).
- Oct 26–31: 2 clicks, 31 impressions.
- Oct 28–Nov 2: 3 clicks, 63 impressions. That's moving in the right direction, but it's still tiny.
- Visits to the new programmatic pages: 0 recorded in analytics from launch through Nov 1. On Nov 3, Google sent the site 0 sessions.
A few days is nowhere near enough time to judge programmatic SEO. Google has to discover, crawl, render and evaluate hundreds of new URLs, and on a small site that usually takes weeks. The pages went live Oct 30, the clean sitemap went in Nov 1, and internal links went live Nov 1. The clock really started on Nov 1.
What we're watching for the follow-up:
- Indexed count for the for-sale sitemap in Search Console
- Impressions on category pages, especially make + model + state, where competition is lowest
- Visits and inquiries from those pages, which needs inquiry tracking we haven't wired up yet (that's on the list)
We'll publish the 30-day numbers around Dec 1, including if the answer is "Google mostly ignored them."
How to apply this to your business
You don't need 5,000 listings. The same pattern works for any business with structured data:
- A contractor with jobs in 15 towns → service + town pages, only where you have real projects, reviews or photos for that town.
- A real estate team → neighborhood pages built from actual listings and sales.
- A restaurant group or multi-location shop → location pages with real hours, menus and reviews.
The rules carry over:
- Set a minimum-data threshold for every page type, and noindex anything below it.
- Make each page different with real data, not swapped keywords.
- QA as Googlebot before you call it done, and expect a v2.
- Keep your sitemap honest: live, useful pages only.
- Link to new pages from places Google already crawls.
- Wait, measure, and report the boring numbers.
This is a real, anonymized experiment from a business we operate. Numbers come from Google Search Console, our analytics and live checks of the site on the dates shown. Results for the new pages aren't in yet, and we'll say so until they are.