Programmatic SEO for B2B: how we ranked AKS across 81 Turkish provinces
A field guide to programmatic SEO for B2B service companies — the same pipeline we used to launch 400+ province-specific pages for AKS Otomasyon and get them ranking in the top 10 within six weeks.

TL;DRProgrammatic SEO works for B2B services when three things hold: the search intent maps cleanly to a variable (usually geography, sometimes vertical), each generated page has genuinely different content (not just token substitution), and you have internal links to prevent orphan-page indexing failures. We ran this playbook for AKS Otomasyon in Q2 2026 and hit top-10 rankings on "il + endustriyel otomasyon" long-tail queries within six weeks of launch.
Programmatic SEO — pages generated from a template plus a dataset — carries a reputation problem. Half the industry writes it up as "low-effort long-tail content" and the other half calls it "thin content that Google will punish." The reality is neither: it's a specific tool that works when a specific set of conditions hold, and fails predictably when they don't.
This post walks through the pipeline we used to launch AKS Otomasyon's programmatic SEO layer in Q2 2026 — 400+ province-specific service pages ranking in the top 10 of Google Turkey for long-tail industrial-automation queries within six weeks of launch.
When programmatic SEO is the right tool
Three conditions have to be true:
1. Search intent maps cleanly to one or two variables. Usually
geography (city, province, region, country) or vertical (industry,
product category, use case) or occasionally a combination of both. For
AKS, the variable was the 81 Turkish provinces (iller), because that's
how industrial buyers actually search: "kayseri endustriyel otomasyon"
not "endustriyel otomasyon" alone.
2. Each generated page can have genuinely different content. Not "welcome to our services in Kayseri" changed to "welcome to our services in İstanbul." Different opening context, different local references, different case studies (where available), different photo. If your template only supports token substitution, you'll trip Google's duplicate content heuristics and none of your pages will rank.
3. You have a hub-and-spoke internal linking pattern. Generated pages need entry points from your main navigation and cross-references between each other. Orphan pages — pages that exist in your sitemap but nothing on your site links to — get discovered but not prioritized.
If any of these three is missing, don't do programmatic SEO. Write a smaller number of longer pages instead.
The AKS setup
AKS Otomasyon sells industrial automation solutions across Turkey. Their original site had one generic services page. A buyer in Konya searching "konya endustriyel otomasyon" would land on a homepage that treated them like a national visitor, and click away.
We wanted every province to have its own page. Not because the service differs (it doesn't), but because search intent differs — a Konya buyer is checking whether AKS is a real vendor for their region, and a national landing page doesn't answer that.
Here's the file structure we ended up with:
src/app/[locale]/hizmetler/
├── endustriyel-otomasyon/
│ ├── page.tsx — hub page (national)
│ ├── il/
│ │ └── [ilSlug]/
│ │ └── page.tsx — one page per province
├── plc-scada/
├── enerji-otomasyonu/
└── ...
The [ilSlug] dynamic segment uses generateStaticParams over an
81-item seed dataset in TypeScript:
export const IL_DATASET = [
{
slug: "istanbul",
name: "İstanbul",
osb: ["Tuzla OSB", "İkitelli OSB", "Beylikdüzü OSB"],
industrialContext:
"Türkiye'nin en yoğun sanayi bölgesi. Otomotiv yan sanayi, gıda paketleme, ilaç üretimi ağırlıklı.",
nearbyIller: ["kocaeli", "tekirdag", "bursa"],
},
{
slug: "kayseri",
name: "Kayseri",
osb: ["Kayseri OSB", "İncesu OSB"],
industrialContext:
"Mobilya, metal işleme ve otomotiv yan sanayi merkezi. OSB'lerin yoğunluğu yüksek.",
nearbyIller: ["nevsehir", "sivas", "malatya"],
},
// ...81 total
];
Every province has real data: OSB names (Organized Industrial Zones — these are the search terms real buyers use), a short industrial context paragraph specific to the province, and adjacent provinces for internal linking.
The template that isn't just a template
Here's where most programmatic SEO fails: the page just repeats the national copy with the city name inserted. Google's algorithms have been tuned against this for a decade. It doesn't work.
Our template pulls province-specific content in three places:
1. Opening paragraph references the industrial context of the province explicitly. "İstanbul'da endüstriyel otomasyon hizmeti veriyoruz — Tuzla OSB'den İkitelli OSB'ye kadar, otomotiv yan sanayi ve gıda paketleme fabrikalarında PLC, SCADA ve enerji otomasyonu projeleri teslim ediyoruz." Different for every province.
2. Related-project block shows real case studies where AKS worked in that province, if any. Empty for provinces where no project has happened yet, replaced by a "İlk projede referans olma fırsatı" CTA. Both variants are valid content — thin-content risk avoided.
3. Cross-links to nearby provinces in a footer block. "Yakın iller"
links to the nearbyIller slugs from the dataset. Every page has 3-4
outbound internal links to other generated pages, which is what tells
Google these are real pages worth crawling, not orphans.
Schema markup at scale
Each generated page emits its own LocalBusiness + Service JSON-LD:
{
"@context": "https://schema.org",
"@type": "Service",
"provider": {
"@type": "LocalBusiness",
"name": "AKS Otomasyon",
"areaServed": {
"@type": "AdministrativeArea",
"name": ilData.name,
"containedInPlace": { "@type": "Country", "name": "TR" }
}
},
"serviceType": "Endüstriyel Otomasyon",
...
}
areaServed scoped to the province is what makes AI Overviews and local
search treat these as genuinely local pages, not national pages with a
city name tag.
What actually happened
Launched in April 2026. First indexed pages showed up in Search Console about 10 days after publish. By week six, we had:
- 400+ province × service combinations indexed.
- Top-10 rankings on ~35 "il + service" long-tail queries.
- Contact form leads tagged by province, which changed how AKS's sales team prioritized follow-up.
Not every page ranks. Some provinces simply don't have enough search volume for the query to matter, and those pages sit in the tail. That's fine — they cost effectively nothing to render (SSG-first) and they're there when future demand appears.
What we'd do differently
Two things.
One: we underestimated how much internal linking matters. The first
version had a page-per-province but no nearbyIller cross-links.
Indexation was slower than expected. Adding the "Yakın iller" block in
week 3 doubled the crawl rate on new pages.
Two: we should have generated the seed dataset from an authoritative source (Wikipedia's TR il list, OSB database) rather than typing it. The first version had a couple of typos in OSB names, which we caught only in QA. When you're generating 400+ pages, source-of-truth data matters more than it does for hand-written content.
When not to do this
Programmatic SEO is not a substitute for depth. If your product has three real customer segments, you want three excellent pages, not thirty mediocre ones templated across false variables. The AKS case works because 81 provinces is a real segmentation — a buyer in Konya cares whether the vendor operates in Konya. But if you're a SaaS with one buyer persona globally, generating "SaaS for [industry]" pages across 100 industries is thin content, and Google will treat it as such.
The tool works when it maps to how buyers actually search. Everywhere else it's a shortcut to a manual penalty.
Related work:
- AKS Otomasyon case study — the full brief.
- Moditra case study — how we approach multi-tenant B2B SaaS, which shares many of the same "one template, many contexts" principles.
- Praxvon SEO services — how we work with programmatic SEO in client projects.