Most programmatic SEO builds I have seen on UK service-business sites are 200 pages of duplicate-content slop that Google ignores. The template gets written once, the city names get plugged in, the body copy reads identical across slugs, and the whole set gets demoted as low-value mass-produced content.
Here is the build log of how I did it without falling into that trap. Live proof at consentleads.uk/locations/.
The shape of the build
8 verticals × 10 UK cities = 80 base pages. Hair salons, barbers, nail salons, aesthetic clinics, dental practices, chiropractors, physiotherapists, pilates studios. London, Manchester, Birmingham, Leeds, Glasgow, Edinburgh, Bristol, Liverpool, Newcastle, Sheffield. Each pair is its own slug like /locations/hair-salons-manchester.html.
Plus 90+ vertical landing pages, comparison pages, and SEO-by-vertical pages built on the same data architecture. Total: 170+.
The duplicate-content trap, and how to dodge it
The standard programmatic-SEO failure mode looks like this. Someone writes one template that says "Looking for the best [VERTICAL] in [CITY]? [BUSINESS_NAME] is the leading [VERTICAL] in [CITY] with 5-star reviews." Then they plug in 200 combinations. Google reads 200 nearly-identical pages, identifies the template, and treats the whole set as one piece of content. None of them rank.
The fix is data depth, not template cleverness. Each page needs at least three layers of genuinely unique content:
- Vertical-specific layer: The keywords, the search intent, the typical customer behaviour, the GBP categories that apply, the schema subtype (Locksmith versus HairSalon versus DentalClinic). This layer is the same across all 10 cities of one vertical.
- City-specific layer: Population, postcode patterns, dominant neighbourhoods, transport patterns that affect catchment, local competitive density. This layer is the same across all 8 verticals of one city.
- Vertical-city intersection layer: This is where the uniqueness lives. Why hair salons in Manchester are different from hair salons in Leeds. Why dental practices in Glasgow operate differently from dental practices in Edinburgh. Local commercial patterns, demographic skews, competitor archetypes.
If your data source can support all three layers per slug, you can scale. If it can only support the first two, you are writing duplicate content with extra steps.
The schema deployment
Every page on the set carries at least four schema blocks:
WebPagewithSpeakableSpecificationso voice assistants can read the answer-block aloudServicewith the right schema.org subtype for the vertical (HairSalon, Dentist, MedicalBusiness, ExerciseGym)BreadcrumbListshowing Home › Locations › [Vertical] [City]FAQPagewith the 5 vertical-city-specific questions buyers actually ask
The FAQ schema is the highest-leverage of the four. It is the structured-data block Google extracts for AI Overviews and ChatGPT pulls for citations. Three to five well-structured FAQ answers per page beats a 2,000-word essay for AI search visibility.
Internal linking that flows equity
The mistake is building 170 leaf pages with no parent hub. Each leaf has zero internal links pointing in, so Google sees them as orphans and deprioritises the whole set.
The structure I built:
Homepage
→ /services/programmatic-seo.html (the product page)
→ /locations/ (the hub)
→ 80 leaf pages, grouped by vertical
→ each leaf cross-links to 2 siblings
(next city in same vertical, same city different vertical)
The hub at /locations/ alone passes link equity to every leaf in the set. Each leaf-to-leaf cross-link creates additional internal flow. Net effect: every leaf has at least three internal links pointing in, not zero.
What worked
- The schema-first deploy. Putting structured data in before the body content was written meant every page was AI-extractable from day one. AI Overviews started picking up FAQ answers in week three.
- The 3-layer data model. Genuine vertical-city intersections kept duplicate-content detectors from triggering. Google has indexed 100 percent of the set so far.
- The hub-and-spoke link structure. Leaf pages are inheriting authority from the hub, not floating as orphans.
What did not
- Pre-seeding GBP-style review counts on leaf pages. Faked review counts looked like spam to Google's quality algorithm. Removed them; pages improved.
- Trying to rank for "[vertical] [city]" head terms on day one. Those SERPs are owned by aggregators (Treatwell, Booksy, Yell). The wins are on long-tail intent queries like "where to find [vertical] in [city]" or "[vertical] [neighbourhood]".
- Skipping the parent hub at first. I did this initially. The leaf pages were orphans for two weeks before I built the hub. The hub was the single biggest lift in indexing rates.
If you want this on your domain
I run this as a productized build at consentleads.uk/services/programmatic-seo.html. Three tiers:
- Starter: 50 pages, £2,500 fixed, 2 weeks
- Standard: 200 pages, £5,000 fixed, 3 weeks
- Scale: 500 pages, £8,000 fixed, 4 weeks
All built on the same 3-layer data model. Code transferred to your domain on payment. No retainer attached. The hub-and-spoke architecture is part of the standard scope.
If you want to see what you would be buying before buying, visit /locations/ and view-source on any leaf page. The schema, the internal linking, the unique-content discipline are all visible in the markup.