Local keyword generation is a multiplication: services times locations times modifiers. The grind version writes every cell of that matrix into a page and gets penalized for it. The smart version generates the full matrix, then lets evidence pick the cells that deserve to exist.

Here is the city-by-city system without the junk pages.

Step 1: build the matrix

List your services down the side, your geography across the top: cities, then the neighborhoods and landmarks locals actually say.

Austin Round Rock South Congress emergency plumber water heater install drain cleaning real: high demand real: suburb searches thin: skip the page real: worth a page maybe: check demand thin: skip real: worth a page maybe thin: skip The matrix generates candidates. Demand evidence decides which cells become pages, and "skip" is a valid verdict.
Every cell is a candidate keyword. Only the evidenced cells become pages, which is what keeps this out of doorway territory.

This is the matrix method with geography as the modifier axis. Build it complete; prune it hard.

Step 2: mine the real local phrasings

Autocomplete knows how each city talks. Run "[service] [city]" seeds through the generator and harvest what locals actually append: neighborhoods, "open now", "cost", specific problems.

Then flip it: "[city] [service]" and "[service] near" completions expose the phrasing order and the near-variants people use. Local question sweeps, "how much does [service] cost in [city]", feed the FAQ layer of every city page, straight out of the question workflow.

Step 3: add the local modifier stack

Modifier groupExamplesThey signal
Urgencyemergency, 24 hour, same day, open nowHighest-value calls
Trustlicensed, insured, certified, reviewsComparison-stage buyers
Pricecheap, affordable, cost, free estimateBudget shoppers, quote intent
Proximitynear me, nearby, in [neighborhood]Resolved by GBP, not pages

The proximity row carries the most misunderstood fact in local SEO: "near me" is not a page you build. Google resolves it from the searcher's location and your Google Business Profile, so that demand is won in your profile, categories and reviews, not in a landing page titled "plumber near me".

Step 4: let evidence pick the pages

For each surviving matrix cell, two checks. Demand: does the phrase or its variants show volume, or at least appear in autocomplete? Substance: can you write something specific to that location, real projects, local reviews, area knowledge, directions?

A cell needs both to become a page. Demand without substance produces the swapped-city-name template that Google's doorway policy exists for; substance without demand produces a lovely page nobody asked for.

Step 5: structure as a hub, publish in tiers

Structure follows the pruned matrix: a hub per metro, city pages under it, and service-city pages only for the proven high-value combinations. Everything else gets covered by a section on the parent page instead of a page of its own.

Publish in tiers too: your home city's full set first, then the strongest suburb, watching what ranks before expanding. Local SEO rewards depth in a tight radius over thin national sprawl, the same ladder logic as the new-niche playbook.

The differentiation test

Before publishing any city page, read it next to its sibling with the city names covered. If you cannot tell which city each describes, neither can Google, and the page is a liability wearing a keyword.

The fix is always the same: local proof. One paragraph about actual work in that area, three reviews from its residents and accurate service-area lines beat five hundred words of template.

The one-line takeaway: generate the full service-times-location matrix, mine autocomplete for how each city really phrases it, then let demand plus local substance decide which cells become pages. Near-me lives in your business profile, and thin city clones live nowhere good.