Case study / Plumbing · Programmatic Local SEO
Streamlined Plumbing.
A 400-page plumbing platform for Baldwin County — 308 hand-authored city × service pages, each carrying real municipal-water, elevation, and flood data for its own city.

fig. 01 — Homepage — symptom-first entry, real crew photo
What the build
actually moved.
What the project
needed to do.
Streamlined Plumbing is a master-licensed (AL MP-4462), owner-operated plumbing company in Fairhope, Alabama, serving 22 cities across Baldwin County. Campbell Digital Studio replaced its GoDaddy site with a 400-URL Next.js platform: a 308-cell city × service matrix across 22 cities and 14 services, 22 city hubs, 14 service pages, a 63-post local field guide publishing on a weekday drip, five interactive diagnostic tools, and a photo gallery built entirely from the owner's own job photos. The differentiator is the content layer — every matrix cell was hand-authored against a per-city data snapshot (EPA SDWIS water systems, USGS groundwater chemistry, Census housing age, elevation, FEMA flood zone) rather than rendered from a template, and three CI gates block the build if a page drifts back toward boilerplate or makes a claim the data does not support.
An owner-operated plumbing company in Fairhope was competing for Baldwin County work on a GoDaddy site, against a market where the ranking incumbents run 100–160 pages. The obvious move — spin up a city × service matrix across 22 cities and 14 services — is also the fastest way to get 308 near-identical pages filtered out as doorway spam. The demand shape made it harder: plumbing searches arrive as symptoms, not service names. People search what is happening in front of them — a leak, a clog, no hot water — so the site had to win high-volume symptom queries rather than the tidy service-category terms a trade site usually chases. And every claim had to survive verification against public licence and utility records before it could ship.
308 city × service pages that each say something only true of that city — the mechanism that separates a matrix that ranks from one Google filters as doorway spamWhat moved the needle
What it looks like,
on screen.






The deliverables,
line by line.
A 400-URL Next.js platform whose defining work is the content layer. Rather than render 308 matrix cells from a template, each was authored against a per-city data snapshot — the municipal water system and PWSID from EPA SDWIS, county groundwater pH from USGS, Census housing age, elevation, and FEMA flood zone — with each service reading a different subset of those axes and reaching a different conclusion from the same figure. The acceptance criterion was the swap test: remove the city name from a paragraph, and if it still reads sensibly, rewrite it. On top of that sit 22 city hubs, 14 service pages, a 63-post local field guide on a weekday drip, five interactive diagnostic tools, and an /our-work gallery built from 48 of the owner's own job photos. The homepage leads with the symptom rather than the service menu, matching how the business's actual demand arrives. Three CI gates — matrix-claims, matrix-duplication, matrix-registry — each with a self-test fixture, block the build if a page drifts toward boilerplate or asserts something the data does not support.
- 308-cell city × service matrix — 22 Baldwin County cities × 14 services, every cell individually authored (median 3,819 words) rather than template-rendered
- Per-city data layer in every cell — municipal water system and PWSID (EPA SDWIS), county groundwater pH (USGS), elevation, FEMA flood zone, and Census housing age, each field carrying its source
- The salience model — each service reads a different subset of the city's data and draws a different conclusion from the same number, so 22 fact-sets produce 308 distinct pages instead of 308 paraphrases
- 22 city hub pages (median 3,297 words) and 14 service pages (median 3,179 words)
- 63-post local field guide — coastal and Baldwin-specific plumbing writing (condo riser stacks, freeze-event triage, cast-iron drain lines, county water chemistry); 11 live, the rest drip-publishing weekdays through December 2026
- Five interactive client-side tools — plumbing symptom checker, water-waste calculator, tank-vs-tankless sizing, repipe cost estimator, grinder-pump checker — each citing EPA/DOE figures
- Symptom-first homepage — the primary entry point is 'what's happening?' rather than a service menu, matching how emergency plumbing demand actually arrives
- Photo library built from the owner's own work — 48 real job photos catalogued and placed with no duplicates, plus an /our-work gallery labelled 'not stock images'
- Three CI gates — matrix-claims, matrix-duplication, and matrix-registry — each with its own must-catch/must-pass self-test fixture
- Rendered-output duplication checking — shingle overlap measured over built HTML, not source, so shared template text on all 308 cells cannot hide behind a green source-level scan
- Plumber and LocalBusiness schema under one canonical entity, 24/7 hours modelled in OpeningHoursSpecification, and 10 legacy GoDaddy → new-URL 301s in middleware
- Next.js on Vercel, with the apex indexable at DNS cutover by host-conditional robots headers rather than a flag someone has to remember to flip
How the build
earns the call.
Every city × service intersection is a standalone indexed page made non-duplicate by data, not by paraphrase: Fairhope's page cites PWSID AL0000035 and a 5.9 median groundwater pH across 248 USGS samples, and says plainly that those are raw well samples rather than treated tap water. That is the whole mechanism — a page that can point at a field says something a competitor's template cannot. Duplication is measured over rendered HTML rather than source, because a template lives in one file and never collides with itself no matter how many pages it renders onto. The build carries Plumber and LocalBusiness schema under one canonical entity, 24/7 hours in OpeningHoursSpecification, and 301s from the 10 legacy GoDaddy URLs. 400 URLs are live on the sitemap today, rising to 452 as the field guide finishes publishing in December. The site launched in August 2026 and the apex became indexable at DNS cutover — search and lead outcomes are still ahead of it and none are claimed here.
Gives a small, master-licensed plumbing company a findable page for every service in every Baldwin County city it covers — built to survive doorway-page scrutiny because the pages carry real local facts rather than reworded boilerplate. Every service line on the site is one the owner confirmed in writing, and the build states plainly where the company's scope ends rather than inheriting a template's claims. The site is new: this is the foundation — the architecture, the content layer, and the gates that keep it honest — not a performance report. What the platform buys is a front door built on the symptom searches the business actually earns its living from.
A 308-cell city × service matrix is the fastest way to build a doorway-spam penalty. The usual failure is a template that swaps the city name into the same paragraph 308 times. This build was hand-authored instead: every cell carries data drawn for that specific city — the municipal water system and its PWSID, county groundwater chemistry, elevation, flood zone, housing age — and each service reads a different subset of it. Fairhope's soft, acidic groundwater is the reason the drain-cleaning page there talks about older service lines; Bay Minette's elevation is why grinder pumps are rare there and sump-pump discharge has fall to work with. The acceptance test was blunt: delete the city name from a paragraph, and if it still makes sense, the paragraph gets rewritten.Studio rationale
Metrics, captured
at 30 / 60 / 90 days.
Tracking dashboard captures GSC + GA4 at 30 / 60 / 90 days. Report publishes here on day 90 — view tracking spec