Fixing Multi-Location SEO on Your Website
A business with several branches needs its website to do what a single-location site never has to: give every branch its own address on the web, let people and search engines reach each one, and keep dozens of addresses, phone numbers and opening times correct at once.
The usual failures are a map widget that hides branch links from crawlers, branch pages that are copies with a new postcode, and markup that lumps every location into one block on the homepage. This guide covers the website side: the locator, the branch pages, per-branch markup and what to do when branches open, move or close.
- How multi-location websites lose local visibility
- A site structure that scales from three branches to three hundred
- Making the store locator crawlable
- What every branch page needs
- LocalBusiness markup per branch
- One source of truth for branch data
- Openings, moves and closures on the website
- The fix, step by step
- Questions and answers
How multi-location websites lose local visibility
Most chains, franchises and practice groups do not have a content problem so much as a plumbing problem. The information exists somewhere, usually in a head-office spreadsheet, but the website does not expose it in a way that search engines can use. The common patterns look like this:
- One "Find us" page for everything. Twelve addresses listed on a single contact page. None of the branches has a page of its own that a Business Profile can link to or that can rank for a search in its town.
- A map with no links. The locator is a JavaScript widget that loads branch pins from
an API after the page has loaded. A person can click a pin; a crawler sees an empty
<div>. - Branch pages behind a query string. Each branch opens at
/stores?id=317, sometimes with the same title tag on every one, and nothing links to those URLs except the widget. - Copied branch pages. Every page has the same four paragraphs with the town name swapped. Search engines see a set of near-duplicates and may pick one to show and ignore the rest.
- Homepage markup listing every branch. A single JSON-LD block with an array of twenty addresses, which says nothing clear about any of them.
- Closed branches returning 404. A branch shuts, its page is deleted, and every link and bookmark to it breaks, while the Business Profile still points at the dead URL.
The Business Profile side of this, including business groups, bulk verification and store codes, has its own guide: managing multi-location Business Profiles. Everything below is about the website those profiles link to.
A site structure that scales from three branches to three hundred
Every branch needs one permanent, readable URL. How deep the structure goes depends on how many branches you have.
| Branches | Suggested structure | Example |
|---|---|---|
| 2 to 10 | Locations index, then one page per branch. | /locations/ โ
/locations/harrogate/ |
| 10 to 60 | Index, optional region pages, branch pages. | /locations/yorkshire/
โ /locations/yorkshire/harrogate/ |
| 60 and up | Index, region or county pages, town pages where there are several branches, branch pages. | /locations/leeds/ listing /locations/leeds/kirkstall/
and /locations/leeds/headingley/ |
Some rules that save trouble later:
- Use the place, not an internal code, in the slug.
/locations/harrogate-station-parade/survives a change of store numbering;/store/0317/tells nobody anything. - Two branches in one town get a street or district in the slug, and the town page (if you have one) lists both.
- Region pages must earn their place. A region page is useful as a navigation step that lists branches with their key details. It should not pretend to be a location in its own right.
- Keep branch URLs out of query strings. If the platform insists on
?store=parameters for the interactive view, give each branch a clean static URL as well and make that the canonical.
Making the store locator crawlable
An interactive map is good for visitors on a phone who want the nearest branch. It is a poor way to tell a search engine which branches exist. The fix is not to remove the map but to put a plain list of links beside it.
Test what a crawler sees
- Open your locator page, then open browser developer tools and disable JavaScript (in Chrome, the command menu has a "Disable JavaScript" option), and reload.
- If the branch names and links vanish, a crawler that does not run scripts sees nothing. Google does render JavaScript, but rendering is deferred, and links that only appear after a search box is used or a map is panned are never discovered.
- Use URL Inspection in Search Console and view the crawled page to see what Google actually rendered.
What to put in the HTML
Output the branch list on the server, as ordinary anchor links, grouped by region if the list is long:
<section aria-labelledby="all-branches">
<h2 id="all-branches">All branches</h2>
<h3>North Yorkshire</h3>
<ul>
<li><a href="/locations/harrogate/">Harrogate, Station Parade</a></li>
<li><a href="/locations/ripon/">Ripon, Market Place</a></li>
</ul>
<h3>West Yorkshire</h3>
<ul>
<li><a href="/locations/leeds/kirkstall/">Leeds, Kirkstall Road</a></li>
</ul>
</section>
The map can load from the same data and sit above the list. Links inside map pop-ups are fine as an extra, but should never be the only route to a branch page.
Platform notes
- Locator plugins and SaaS widgets. Many WordPress store-locator plugins and hosted locator services render only in the browser. Check whether yours can generate static branch pages or a server-side list; if not, add the list yourself from the same data.
- Shopify. Branch pages are often easiest as a page template driven by metaobjects, one entry per branch, with the locator listing them.
- Next.js, Nuxt and similar. Generate branch pages at build time or render them on the server, and make the locator index a server-rendered route rather than a client-only component.
Add every branch URL to your XML sitemap as well. A sitemap helps discovery but does not replace internal links, which also tell search engines how the pages relate.
What every branch page needs
Branch pages share a template. They should not share their text. Split the page into fixed elements that every branch has, and branch-specific material that makes each page worth visiting.
| Element | Same template, different data | Written for this branch |
|---|---|---|
| Name, address, phone | Yes, from the data sheet | |
| Opening hours and holiday hours | Yes | |
| Map and directions link | Yes | Access notes: which entrance, nearest car park, bus stops, step-free route |
| Services and facilities | Checklist from the data sheet | What this branch does that others do not |
| People | Branch manager or practitioners, with a line about each | |
| Photos | The shopfront and inside of this branch, not stock images | |
| Reviews | Pulled for this branch only | |
| Local context | A short, true paragraph: how long you have been there, what the area needs from you | |
| Nearby branches | Links to the two or three closest |
Title tags follow a pattern such as Brand, Harrogate Station Parade | Opticians in Harrogate,
and the H1 names the branch plainly. Avoid putting a list of neighbouring towns in the title; the page
is for the place where the branch is.
LocalBusiness markup per branch
Each branch page carries one LocalBusiness block describing that branch only. The brand is described
once, as an Organization with its own @id, and each branch refers to it through
parentOrganization. (Schema.org's older branchOf property has been superseded
by parentOrganization.)
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Optician",
"@id": "https://example.co.uk/locations/harrogate/#branch",
"name": "Clearview Opticians Harrogate",
"url": "https://example.co.uk/locations/harrogate/",
"telephone": "+44 1632 960412",
"branchCode": "HGT01",
"address": {
"@type": "PostalAddress",
"streetAddress": "7 Station Parade",
"addressLocality": "Harrogate",
"postalCode": "HG1 1AA",
"addressCountry": "GB"
},
"geo": { "@type": "GeoCoordinates", "latitude": 53.99312, "longitude": -1.53821 },
"openingHoursSpecification": [
{ "@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
"opens": "09:00", "closes": "17:30" },
{ "@type": "OpeningHoursSpecification",
"dayOfWeek": "Saturday", "opens": "09:00", "closes": "16:00" }
],
"parentOrganization": { "@id": "https://example.co.uk/#organization" }
}
</script>
- The @id includes the branch URL, so every branch has a distinct identifier that never collides with another.
- branchCode is a schema.org property for your internal reference. Using the same code as the store code on the branch's Business Profile makes cross-checking easier.
- Departments. A branch with a distinct unit inside it that has its own hours or phone
number, such as a hearing centre in an optician, can list it under
departmentas a nested LocalBusiness. - The homepage carries the Organization block with the logo and sameAs links, not a list of every branch.
The finer points of types, hours and coordinates are the same as for a single business and are covered in the LocalBusiness schema guide.
One source of truth for branch data
With more than a handful of branches, the only reliable way to keep details correct is to hold them in one place and generate everything else from it. The same record should feed the branch page, its markup, the locator list and map, and the sitemap.
A workable data sheet has one row per branch and columns for: branch code, public name, street address, town, postcode, phone, email, latitude, longitude, weekly hours, special hours with dates, services offered, manager name, page slug, Business Profile link, status (open, opening soon, temporarily closed, closed) and date last checked.
- Small estates can keep this as a spreadsheet and update pages by hand, provided one person owns the sheet.
- WordPress sites can model branches as a custom post type with fields, so the template, markup and locator all read the same fields.
- Headless or custom sites can hold branches in the CMS or a JSON file checked into the repository, and build pages from it.
Openings, moves and closures on the website
| Event | What to do with the branch page |
|---|---|
| New branch opening | Publish the page a few weeks before opening with the address, an "opening on" date and how to contact you meanwhile. Add it to the locator and sitemap. Switch to normal hours on opening day. |
| Temporary closure (refit, flood) | Keep the page live, add a clear notice with the expected reopening date and the nearest open branch, and update the hours in the markup to match. |
| Move within the same town | Keep the same URL, change the address, map, coordinates and photos, and add a short "we have moved" note for a few months. |
| Permanent closure | Either keep the page with a closure notice and links to the nearest branches, or 301 redirect it to the nearest branch or the region page. Remove it from the locator list and sitemap either way. |
| Two branches merged | Redirect the closing branch's URL to the surviving one and mention the merger on the surviving page. |
A redirect to the nearest branch is right when customers of the old branch will realistically use the new one. If the nearest branch is an hour away, a page explaining the closure and listing options is kinder than a redirect that drops people somewhere unexpected.
The fix, step by step
Step 1
Build the branch data sheet
Create one row per open branch with its code, public name, full address, postcode, phone number, coordinates, weekly and special hours, services, page slug and Business Profile link. Get each branch manager to confirm their own row rather than copying from old marketing material. Mark closed or relocated branches separately so they can be handled later. This sheet becomes the only place details are edited, and everything else on the site is filled from it.
Step 2
Set one URL per branch
Choose
a folder pattern such as /locations/town/, adding a region level only if you have enough
branches to need it and a street or district where two branches share a town. Give every branch a static,
readable URL that does not depend on a query string. If old URLs exist, map each one to its new address
and set up 301 redirects in the same release so no existing links or bookmarks break during the change.
Step 3
Make the locator crawlable
Reload the locator page with JavaScript disabled and see whether branch links remain. If they vanish, add a server-rendered list of plain anchor links to every branch page, grouped by region, underneath or beside the map. Keep the map for visitors, fed from the same data. Add every branch URL to the XML sitemap, then check a branch in Search Console URL Inspection to confirm Google can reach and render the page.
Step 4
Fill each branch page with its own facts
Use a shared template for the name, address, phone, hours, map, services checklist and nearby branches, all drawn from the data sheet. Then add what only that branch can offer: real photos of the shopfront and interior, the people who work there, access and parking notes, services unique to it and reviews left for that branch. Give each page a title and H1 naming the branch and its town, without lists of other places.
Step 5
Add LocalBusiness markup per branch
Output
one JSON-LD block on each branch page describing that branch only, with the most specific type, its own
@id built from the branch URL, full address, coordinates, hours and phone. Link it to the
brand with parentOrganization pointing at the Organization @id on the homepage.
Remove any homepage block that lists every branch. Validate a sample of branches in the Schema Markup
Validator after the template is live.
Step 6
Point each Business Profile at its branch page
For every branch, set the website link on its Business Profile to that branch page rather than the homepage, so people who click from the map land on the right address and hours. Add campaign tracking parameters if you want to separate map clicks in analytics, while keeping the path itself clean. Record the link in the data sheet, and check the details on the profile agree with the branch page before saving the change.
Step 7
Handle openings, moves and closures
Write a short procedure covering each event: publish new branch pages before opening day, keep temporarily closed pages live with a notice, keep the same URL when a branch moves within a town, and either keep a closure notice or 301 redirect permanently closed branches to the nearest sensible alternative. Update the locator, sitemap, markup and Business Profile together each time, and log the change and date in the data sheet.
1. Do I need a separate page for every branch?
Yes, if each branch has its own premises that customers visit. A dedicated page gives the branch a URL that its Business Profile can link to, a place for its own hours and directions, and a page that can appear for searches in its town. A single contact page listing every address cannot do any of those jobs well. The exception is a location customers never visit, such as a warehouse or head office, which does not need a public branch page.
2. Is it a problem that my branch pages look similar?
Sharing a template is normal and expected; sharing the body text is the problem. Search engines understand that branches of one business have the same layout, services list and brand wording. They struggle when the only difference between pages is the address. Add material that is true of one branch only: its photos, staff, access notes, local services and reviews. Where you genuinely have nothing different to say, keep the page short and factual rather than padding it.
3. Can Google find branches in a JavaScript store locator?
Google renders JavaScript, but that does not mean it finds everything a locator can show. Branches that appear only after someone types a postcode, pans the map or clicks a pin are often never discovered, because crawlers do not perform those actions. The dependable fix is a plain HTML list of links to every branch page, rendered on the server alongside the map, plus the branch URLs in your XML sitemap.
4. Should the homepage list all my locations in its schema?
No. Structured data on a page should describe what that page is about. The homepage is about the brand, so it suits an Organization block with the logo, contact details and social profiles. Each branch is described on its own page by its own LocalBusiness block, linked back to the brand through parentOrganization. A single homepage block with an array of every address makes it harder, not easier, to connect each branch to the right location.
5. What should happen to a branch page when the branch closes?
Take it out of the locator and sitemap, then choose between two options. If customers of the closed branch will realistically use a nearby one, 301 redirect the page there. If the nearest alternative is far away, keep the page with a clear closure notice and links to your other branches, and consider adding a noindex tag after a few months. Mark the Business Profile as permanently closed as well, so both agree.
6. Should my Business Profile link to the homepage or the branch page?
Link each profile to its own branch page. Someone who taps the website button from a map result wants that branch's hours, parking and phone number, not the brand homepage where they have to search again. It also keeps the connection between the profile and the page clear, because the address and hours on both should match. Adding tracking parameters to the link is fine, provided the path still points to the branch page.
7. How do franchises handle branch pages when franchisees have their own sites?
Ideally the brand site holds one page per franchise location, built from the same template as every other branch, and the franchisee manages the local material on it. Separate franchisee websites often duplicate the brand's content, compete with the brand page for the same searches and drift out of date. If franchisees must keep their own sites, make sure the details match the brand's branch page exactly, and agree which of the two the Business Profile links to.
The Local SEO Checker looks at NAP consistency across major citation sources, LocalBusiness schema completeness, Business Profile signals, review velocity, geo-content coverage and your position in the map pack, so you can see which branches need attention.
Open Local SEO Fixes โ