Multi-Location SEO
Scaling local SEO across 10, 100, or 1,000 locations: location pages without duplicate content, programmatic local SEO without Helpful Content penalties, GBP API operations, and the service-area-business specifics.
Multi-location SEO is where local SEO meets programmatic SEO and the constraints of both apply. You need a unique GBP profile per location, a unique landing page per location, consistent NAP across hundreds of citations, and a content strategy that does not collapse into templated thin pages — all at scale. The teams that get this right (Domino’s, Chase, Allstate, Sephora) compound traffic. The teams that do not lose sitewide rankings to Helpful Content demotion in a single update.
TL;DR
- Each location needs its own GBP profile and its own landing page. Shared landing pages or shared GBPs for nearby locations actively hurt local pack ranking — the system expects 1:1.
- Templated location pages are Helpful-Content bait. A
[city] [service]template producing 200 thin pages will get demoted as a set, taking innocent pages with it. Differentiation per page is non-negotiable. - Service-area businesses follow different GBP rules. No storefront address shown, multiple service areas configured, separate verification process. The wrong setup leaves you invisible to local searches you should rank for.
The mental model
Multi-location SEO is operating a chain of restaurants. Each location has a manager who knows the local clientele, the parking situation, the dietary preferences of the neighborhood. The HQ provides brand standards, supplier contracts, training. A chain whose stores all feel like cookie-cutter franchises loses to one whose stores feel locally rooted.
Your location pages and GBP profiles are the same: HQ provides the brand template, the schema, the deployment infrastructure. Each location’s page should still feel like a person from that neighborhood wrote it — with photos of the actual storefront, local team, local references, and details that only that location would know.
Deep dive: the 2026 reality
The 1:1 rule
Google’s local pack expects one verified business at one address. Sharing a profile across multiple locations is a guideline violation. Sharing a website page across multiple locations is a duplicate-content problem.
| Setup | Compliant? | Local SEO impact |
|---|---|---|
| 1 GBP per location, 1 landing page per location | Yes | Optimal |
| 1 GBP per location, shared landing page for all | Compliant for GBP, weak for SEO | Reduced rank |
| Shared GBP across nearby locations | Violation | Suspension risk |
| 1 landing page per location, shared GBP | Violation | Suspension risk |
| Service-area business with multiple service areas | Yes (special config) | Optimal for SAB |
Location page architecture
URL structure that scales:
/locations/ # hub page listing all locations
/locations/austin/ # Austin metro hub if multiple Austin locations
/locations/austin/south-lamar/ # specific location
/locations/austin/south-lamar/services/ # location-specific services
For very large operations (Domino’s, Chase) the convention often becomes a flat /locations/[city]-[street] to avoid deep nesting.
What goes on a high-quality location page
Required, unique per location:
| Element | Source |
|---|---|
| H1 with location and brand | ”Acme Plumbing — South Lamar, Austin” |
| Storefront photos | Real, recent, multiple angles |
| Address (matching canonical NAP) | Sourced from authoritative location DB |
| Embedded map with pinned address | Google Maps embed |
| Phone number (local, not national 800) | Per-location |
| Hours including special hours | Per-location |
| Team photos and bios | Per-location |
| Customer reviews filtered to that location | Per-location |
Local schema (LocalBusiness with @id) | Per-location |
| Services offered at that location | Per-location (some locations may not offer all) |
| Pricing if applicable | Per-location (varies by market) |
| Local content blocks | Per-location (neighborhood notes, events, regional regulations) |
| Internal links to nearby locations | Auto-generated by proximity |
| Internal links to relevant city blog content | Editorial-curated |
The per-location column is what differentiates a high-quality page from a thin template. Each item should have actual unique data, not “Insert City Name Here” substitution.
The thin-template trap
The classic anti-pattern:
<h1>Best [SERVICE] in [CITY], [STATE]</h1>
<p>Looking for the best [SERVICE] in [CITY]? Acme has been
serving [CITY] residents since 2014. Our experienced team
of [SERVICE] professionals is committed to providing
[CITY] with the highest quality [SERVICE].</p>
<p>If you live in [CITY] and need [SERVICE], call Acme today.</p>
Multiplied across 200 cities, this is a Helpful Content classifier landmine. The 2024 March core update + 2025 Helpful Content refresh demoted thousands of these pages — sitewide, not page-by-page. Recovery is hard.
The differentiated template that survives
<h1>Acme Plumbing - South Lamar, Austin</h1>
<p class="location-meta">1234 S Lamar Blvd, Austin, TX 78704
<span>Open today 8am-6pm</span></p>
<section class="hero">
<img src="/locations/south-lamar/storefront.jpg"
alt="Acme Plumbing storefront on South Lamar">
<p>Our South Lamar location has served South Austin homeowners
since 2018. Master plumber Joe Garza leads a team of 6 licensed
technicians, with same-day service across 78704, 78745, and 78704.
South Austin's older 1950s and 1960s housing stock means we
specialize in cast-iron pipe replacement and slab leak repair.</p>
</section>
<section class="services">
<h2>Services at this location</h2>
<ul>
<li>Slab leak detection (specialty) - $295 starting</li>
<li>Cast iron pipe replacement (specialty) - $4,500-12,000</li>
<li>Same-day water heater install</li>
<li>Sewer line camera inspection - $325</li>
</ul>
</section>
<section class="team">
<h2>Your South Lamar team</h2>
<!-- 4 team member cards with photos and bios -->
</section>
<section class="reviews">
<h2>What South Lamar customers say</h2>
<!-- 5 most recent reviews filtered to this location -->
</section>
<section class="local-context">
<h2>South Austin plumbing notes</h2>
<p>South Austin's mix of 1950s ranch homes and newer construction
means a wide range of plumbing systems. Our most common service
calls in 78704 are slab leaks (35% of work) and cast iron pipe
replacement (22%). Travis County permit fees for major work run
$85-450 depending on scope. We pull permits and handle inspection
scheduling at no additional fee.</p>
</section>
Each location’s page has unique local data that only that location’s team could write. That is what passes the Helpful Content evaluation.
Programmatic local SEO done right
For 50-1000 locations, manually writing each page is not feasible. Programmatic generation is — provided each page is unique, useful, and validated.
Workflow:
// Pseudocode
async function generateLocationPage(loc: Location): Promise<LocationPage> {
const baseTemplate = await loadTemplate('location-page');
const localData = {
storefrontPhoto: await loadPhoto(`storefront-${loc.id}`),
teamMembers: await db.team.where({ locationId: loc.id }),
reviews: await db.reviews.where({ locationId: loc.id }).limit(8),
services: await db.services.where({ locationId: loc.id }),
localContext: loc.localContextBlocks, // human-written per location
nearbyLocations: await proximityQuery(loc.coords, 25),
citySchema: await loadCityEntity(loc.city)
};
if (!localData.localContext || localData.localContext.length < 200) {
throw new Error('Location missing required local context');
}
return render(baseTemplate, { loc, ...localData });
}
Critical guardrails:
- Validation: any page failing the local-context check is excluded from publication.
- Manual review: a 1-5% audit sample reviewed monthly.
- Sitewide quality monitor: alerts if average words-per-page or unique-content ratio drops.
- Kill switch: noindex toggle and removal procedure if Helpful Content scores degrade.
This is Module 18’s pSEO discipline applied to local. The data behind each page is the moat.
GBP at scale
For 10+ locations, manual GBP management is impossible. Use the Business Profile API for bulk operations.
import { google } from 'googleapis';
const auth = new google.auth.GoogleAuth({
credentials: JSON.parse(process.env.GBP_SERVICE_ACCOUNT),
scopes: ['https://www.googleapis.com/auth/business.manage']
});
const information = google.mybusinessbusinessinformation({ version: 'v1', auth });
// Bulk update hours for 247 locations on holiday
async function setHolidayHours(locations, date, opens, closes) {
for (const loc of locations) {
await information.locations.patch({
name: `locations/${loc.gbpId}`,
updateMask: 'specialHours',
requestBody: {
specialHours: {
specialHourPeriods: [{
startDate: { year: 2026, month: 12, day: 25 },
endDate: { year: 2026, month: 12, day: 25 },
openTime: opens,
closeTime: closes,
closed: false
}]
}
}
});
}
}
For non-engineering teams, Yext, BrightLocal, Synup, or Birdeye provide multi-location dashboards.
Service-area businesses (SAB)
A service-area business has no storefront where customers visit — they go to the customer (plumbers, mobile groomers, locksmiths, electricians). GBP setup is different:
| Setting | Storefront | Service-area |
|---|---|---|
| Storefront address visible | Yes | No, hide it |
| Service areas configured | Optional | Required (up to 20) |
| Categories | ”[Type]" | "[Type]” with “Mobile” or “Service” prefix where available |
| Verification | Postcard or video | Often video, sometimes phone |
Common SAB mistake: configuring 20 service areas covering an entire state. Google penalizes overly broad service areas. Stay within actual operating radius (the area you genuinely service same- or next-day).
Multi-location citation management
A 50-location operation needs 50 NAP records, each with its own canonical address, phone, and hours. Citation management at this scale requires:
- A single source of truth (your CMS, PIM, or a master spreadsheet)
- A propagation tool (Yext, BrightLocal, Moz Local, Synup)
- A change management process (location moves, phone changes, closures)
- A verification cadence (quarterly NAP audits per location)
A misconfigured citation in 1 of 50 locations is hard to spot but degrades that location’s local pack ranking. Centralized management prevents drift.
Visualizing it
flowchart TD
A[Master location database] --> B[Per location GBP via API]
A --> C[Per location landing page]
A --> D[Per location citation deployment via Yext or BrightLocal]
C --> E{Quality gate}
E -->|unique local context >= 200 words| F[Publish]
E -->|fails check| G[Block from publish]
F --> H[Sitemap submission]
B --> I[Local pack ranking]
D --> I
H --> I
I --> J[AI Overview merchant carousel]
I --> K[Maps visibility]
Bad vs. expert
The bad approach
A 120-location restaurant chain rolls out programmatic location pages. The template:
<h1>{name} {city} Location</h1>
<p>Welcome to {name} in {city}, {state}. Our {city} restaurant
serves the best {cuisine} food in town. Stop by today!</p>
<p>Address: {address}</p>
<p>Phone: {phone}</p>
<p>Hours: {hours}</p>
120 pages publish overnight. The total unique content per page is about 30 words. The team also creates 120 GBP profiles, one per location, but uses the same homepage URL for every profile. Three months later the March 2026 core update demotes the entire site by 62% organic traffic.
This fails because 120 near-identical pages trigger the Helpful Content classifier. The shared homepage URL across GBP profiles dilutes the per-location ranking signal. The brand was visible enough to draw scrutiny but not differentiated enough to survive it.
The expert approach
Same chain. The team builds a content production pipeline:
production:
base_template: location_page_v3
required_unique_blocks:
- storefront_photo: original_per_location
- team_bios: per_location
- location_specific_menu: per_location
- manager_quote: 60-80_words_per_location
- neighborhood_context: 150-200_words_per_location
- local_partnerships: per_location
validation:
min_unique_words_per_page: 350
plagiarism_check: copyscape_internal
schema_validation: rich_results_test
publication_cadence: 8_locations_per_week
qa_audit: 1_in_5_pages_human_reviewed
gbp:
one_profile_per_location: true
landing_url: "{base}/locations/{city}/{slug}"
api_management: googleapis
citation_propagation: yext
Content team writes 350-500 unique words per location page (manager interviews, local partnerships, neighborhood notes). Photos shot per location. Reviews filtered per location.
After 18 months: 117 of 120 pages indexed (3 closed during the period), local pack #1 in 84 of 120 markets, organic traffic up 240% YoY, survives core updates intact.
This works because each page passes the Helpful Content evaluation on its own merits, and the site benefits from the cumulative geographic signal of 120 high-quality location pages.
Do this today
- Build a single source of truth for location data: database table or sheet with id, name, address, lat/lng, phone, hours, services, manager, photo paths, NAP variants. This is the spine of everything else.
- Audit existing location pages. Run Screaming Frog with the “Near Duplicates” report enabled. Anything with similarity above 80% to other location pages is a candidate for rewrite or deletion.
- For each location, write or commission 350-500 words of unique local content: neighborhood specifics, local team bios, local pricing notes, partnerships, regulations. Block templated thin pages from publishing.
- Standardize URL structure.
/locations/[city]/[slug]works for most operations. Avoid query strings, mixed cases, and trailing-slash inconsistency. - Add LocalBusiness schema with unique
@idper location. Validate via Rich Results Test. Cross-link locations withrelatedLinkif relevant. - For 10+ locations, enable the Google Business Profile API at
developers.google.com/my-business. Use it to bulk-update hours, photos, and posts. Manual updates do not scale. - Set up multi-location citation management via Yext, BrightLocal, Moz Local, or Synup. Standardize NAP. Review evaluation criteria (lock-in vs portability) before signing.
- For service-area businesses, configure GBP correctly: hide storefront address, set service areas to actual operating radius, choose mobile/service categories where available.
- Set a quality monitor: monthly Search Console performance per location-page directory. Pages with no impressions in 60 days get rewritten or removed. Helpful Content scores depend on the average, not the best.
- Build a change management runbook for location moves, closures, openings, and rebrands. Include: GBP update sequence, citation update sequence, redirect plan for old URLs, schema updates, sitemap regeneration.
Mark complete
Toggle to remember this module as mastered. Saved to your browser only.
More in this part