You build a fast, clean, beautiful website for a local plumber. Lighthouse scores in the 90s, proper headings, a tidy contact form. You launch it, hand over the keys and move on. Three months later, the plumber emails you: "We're still not showing up on the map when people search for plumbers in town."
The site wasn't the problem, or at least not the whole problem. Local SEO for small business is about half Google Business Profile, which lives entirely outside your codebase, and half website details that developers rarely think about until something goes wrong.
This guide is for developers and freelancers who build sites for local service businesses (plumbers, electricians, salons, cleaners, contractors) and for technical owners doing it themselves. I'll cover how local rankings actually work, the Business Profile rules that affect your build, site architecture that doesn't trip Google's spam policies, treating business details as code, LocalBusiness structured data, the conversion details local customers need, reviews and measurement.
Disclosure: I work with the teams behind Nexi Bloom and SEO Site Checker, both mentioned below. Everything else here is based on Google's own documentation.
The Short Version
- Google ranks local results mainly on relevance, distance and prominence. You can't pay for better local rankings.
- The Google Business Profile drives the map results. The website supports it.
- Build one strong page per core service, and only create location pages that have genuinely local content.
- Keep the business name, address and phone number (NAP) in one source of truth in your code.
- Add accurate LocalBusiness structured data, and tag the profile's website link so you can measure what it brings in.
How Local Search Actually Works
When someone searches "plumber near me" or "emergency plumber Westfield," Google usually shows two kinds of results. First comes the map pack, a map with three businesses, powered by Google Business Profile. Below it are the local organic results, regular web pages ranked partly on location relevance. Your website mostly competes in the second, and supports the first.
Google is unusually open about how the map results work. Google's guide to improving local ranking says local results are "mainly based on relevance, distance, and popularity":
- Relevance is how well a Business Profile matches the search. Complete, detailed information helps.
- Distance is how far the business is from the searcher, or from the location in the search.
- Prominence is how well known the business is, including signals like links from other websites and reviews.
Two things follow from this. First, distance is the one factor nobody can change, which is why a business can't rank in the map pack across an entire metro area just by having a great website. Second, Google states plainly that "There's no way to request or pay for a better local ranking on Google." So be wary of anyone who promises otherwise, and set your clients' expectations accordingly.
Google Business Profile: The Part You Can't Code
You won't write any code for the Business Profile, but its setup affects how you build the site, so it's worth understanding. The essentials are verification, an accurate primary category (the strongest relevance signal), relevant secondary categories, hours, services, attributes and plenty of real photos.
Service businesses have extra rules. Under Google's service-area business guidelines, if customers aren't served at the business address, the address should be hidden on the profile. A service-area business can list up to 20 service areas, defined by cities, postal codes or other areas rather than a radius, and the overall area shouldn't extend beyond about two hours' drive from the business. Each service-area business gets one profile covering the whole area.
The business name on the profile should be the real business name, without extra keywords stuffed in. "Westfield Plumbing Co." is fine. "Westfield Plumbing Co. | Best 24/7 Emergency Plumber Drain Cleaning" isn't.
Here's the part that is your job. The profile has a website link, and by default, clicks from it are hard to separate from other Google traffic in analytics. Tag it with UTM parameters so you can measure it:
https://westfieldplumbing.example/?utm_source=google&utm_medium=organic&utm_campaign=gbp_listing
Make sure the page still has a canonical tag pointing to the clean URL, so the parameters don't create duplicates in search.
Site Architecture for Service Businesses
One strong page per core service
A single "Services" page that lists eight services in a paragraph each won't rank for any of them. Each core service the business wants customers for should have its own page with real substance: what's included, how it works, typical timing, rough pricing guidance where the client is comfortable sharing it, photos of real jobs and answers to common questions.
Location pages, without creating doorway pages
Service-area pages ("Plumbing in Cranford," "Plumbing in Scotch Plains") can help, but this is where many local sites get into trouble. Google's spam policies describe doorway abuse, and one of their examples is "pages targeted at specific regions or cities that funnel users to one page." Ten near-identical pages with the town name swapped are exactly that.
So only create a location page when there's something genuinely local to say: jobs completed in that area, local specifics (older homes with particular plumbing, local permit requirements), area-specific FAQs, reviews from customers there and directions or coverage details. If you can't write that content, don't create the page. A strong service page that mentions the areas served is better than a dozen thin ones.
URL structure and internal linking
Keep the structure simple and predictable. A small plumbing business might look like this:
/
├── /services/
│ ├── /services/drain-cleaning
│ ├── /services/water-heater-repair
│ └── /services/emergency-plumbing
├── /areas/
│ ├── /areas/westfield
│ └── /areas/cranford
├── /about
├── /reviews
└── /contact
Link service pages to the relevant area pages and back, add breadcrumbs, and make sure every important page is reachable within a couple of clicks of the homepage.
Businesses with more than one location
If the business has multiple physical locations that customers visit, each one needs its own page, with its own address, phone number, hours and structured data. Don't merge them into one page.
Treat NAP as a Single Source of Truth
Consistency of the business name, address and phone number across the Business Profile, the website and directories matters for local SEO. On the website, the most common way consistency breaks is depressingly simple: the phone number is hardcoded in the header, the footer, the contact page and the schema, and when it changes, someone updates three of the four.
Put it in one config file and import it everywhere:
// config/business.js
export const business = {
name: 'Westfield Plumbing Co.',
type: 'Plumber',
url: 'https://westfieldplumbing.example',
phone: { display: '(555) 555-0142', e164: '+15555550142' },
address: {
street: '12 Main Street',
city: 'Westfield',
region: 'NJ',
postalCode: '07090',
country: 'US',
showStreet: true, // set to false for a service-area business that hides its address
},
geo: { lat: 40.65899, lng: -74.34737 },
hours: [
{ days: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], opens: '08:00', closes: '18:00' },
{ days: ['Saturday'], opens: '09:00', closes: '13:00' },
],
serviceAreas: ['Westfield', 'Cranford', 'Scotch Plains', 'Mountainside'],
profiles: [
'https://www.facebook.com/westfieldplumbing',
'https://www.yelp.com/biz/westfield-plumbing-co',
],
};
Then every template reads from it. In JSX, for example:
import { business } from '../config/business.js';
export function CallButton() {
return <a href={`tel:${business.phone.e164}`}>Call {business.phone.display}</a>;
}
Storing the phone number in both a display format and the international E.164 format means the visible number and the tel: link can never drift apart. When the client changes their hours or moves, you update one file, and the header, footer, contact page and structured data all change together.
LocalBusiness Structured Data That's Actually Right
Structured data tells search engines explicitly what the business is, where it operates and when it's open. Generate it from the same config, so it always matches the visible page:
// lib/local-business-jsonld.js
import { business } from '../config/business.js';
export function localBusinessJsonLd() {
const a = business.address;
return {
'@context': 'https://schema.org',
'@type': business.type,
'@id': `${business.url}/#business`,
name: business.name,
url: business.url,
telephone: business.phone.e164,
address: {
'@type': 'PostalAddress',
...(a.showStreet && { streetAddress: a.street }),
addressLocality: a.city,
addressRegion: a.region,
postalCode: a.postalCode,
addressCountry: a.country,
},
...(a.showStreet && {
geo: { '@type': 'GeoCoordinates', latitude: business.geo.lat, longitude: business.geo.lng },
}),
openingHoursSpecification: business.hours.map((h) => ({
'@type': 'OpeningHoursSpecification',
dayOfWeek: h.days,
opens: h.opens,
closes: h.closes,
})),
areaServed: business.serviceAreas.map((name) => ({ '@type': 'City', name })),
sameAs: business.profiles,
};
}
Render it in a <script type="application/ld+json"> tag on the homepage and contact page, escaping < characters when you inject it, just as you would for any JSON-LD.
A few rules from Google's LocalBusiness structured data documentation are worth knowing:
-
nameandaddressare required. Everything else, includingtelephone,url,geoandopeningHoursSpecification, is recommended. -
Use the most specific type available, like
Plumber,ElectricianorHairSalon, rather than the genericLocalBusiness. - Mark up each location separately for multi-location businesses.
- Geo coordinates should use at least five decimal places.
For a service-area business that doesn't show its street address publicly, include only the address details you actually display, such as the city, region and postal code, and leave out the geo coordinates, as the generator above does when showStreet is false. Then check the result in Google's Rich Results Test.
And set the right expectations with clients. Google says this markup can help with things like knowledge panels, but it doesn't claim LocalBusiness markup improves map pack rankings. It's about accuracy and clarity, not a ranking switch.
The Conversion Details Local Customers Need
Local search visitors usually want to act quickly, often on a phone, sometimes in an emergency. A few details make a big difference:
- A click-to-call button, visible near the top of every page on mobile.
- Hours and service areas that are easy to find, not buried on the contact page.
- A short contact form that works well on a phone. Name, phone, a short message and you're done.
- Trust signals: licence numbers, insurance, years in business and photos of real jobs and real staff.
Maps deserve special attention. A Google Maps embed loads a lot of JavaScript, and putting one on every page, or at the top of the contact page, is a common cause of slow mobile scores. A simple facade loads the map only when someone asks for it:
<div class="map-facade" data-src="https://www.google.com/maps/embed?pb=YOUR_EMBED_CODE">
<button type="button">Show map and directions</button>
</div>
<style>
.map-facade { aspect-ratio: 3 / 2; display: grid; place-items: center; background: #eef2f5; }
.map-facade iframe { width: 100%; height: 100%; border: 0; }
</style>
<script>
document.querySelectorAll('.map-facade').forEach((el) => {
el.querySelector('button').addEventListener('click', () => {
const iframe = document.createElement('iframe');
iframe.src = el.dataset.src;
iframe.title = 'Map showing our location';
iframe.loading = 'lazy';
el.replaceChildren(iframe);
});
});
</script>
The aspect-ratio reserves the space up front, so the page doesn't shift when the map loads, which protects your Cumulative Layout Shift score. If the map sits well below the fold, a plain iframe with loading="lazy" can be enough on its own.
Reviews: Show Them Without Breaking Rules or Performance
Reviews feed directly into prominence, so the site should make leaving one easy. Link to the business's Google review URL from confirmation emails, invoices and receipts, and add a simple "Leave us a review" link on the site.
Two rules matter here. First, don't build a "review gating" flow that asks customers how they feel and only sends the happy ones to Google. Google's policies prohibit selectively asking for positive reviews. If the client wants a fuller picture of what's allowed, Clutchpilot has a guide on how to get more reviews without breaking the rules.
Second, don't mark up the business's own reviews as star ratings in its structured data. Google's review snippet guidelines say that when a business controls the reviews about itself, its pages using LocalBusiness or Organization structured data are ineligible for star review rich results, and that includes reviews shown through an embedded third-party widget. Show reviews to visitors, by all means, but leave aggregateRating out of the business's own JSON-LD.
If you embed a reviews widget, lazy-load it and reserve its space, for the same performance reasons as the map.
Citations and Local Links
Citations are listings of the business on other sites, like Yelp, Facebook, Bing Places, industry directories and the local chamber of commerce. The key is consistency. Every listing should use exactly the same name, address and phone number as the website and profile, which is another reason to keep NAP in one place.
Links from genuinely local sources help prominence too: suppliers and manufacturers, trade associations, local sponsorships, community organizations and local news coverage. What doesn't help is buying links or paying for bulk directory submissions. They're low quality at best and a spam risk at worst.
Measuring Local SEO
You can't improve what you can't see, so set up measurement from day one:
- Google Business Profile performance shows calls, direction requests and website clicks from the profile.
- Google Search Console shows which searches bring people to the site. Watch queries that include town names or "near me."
- Analytics, with the UTM-tagged profile link, separates profile traffic from other search traffic.
- Call tracking can show which channels drive calls, but be careful with NAP. Use dynamic number insertion on the website if you need it, and keep the main business number on the Business Profile and in citations, so consistency isn't broken.
- A baseline technical check. Run a free website audit at launch and every few months, to catch slow pages, missing titles and broken links before they cost the client visibility.
Common Mistakes
- Keyword-stuffed business names on the profile.
- Fake addresses or virtual offices used to appear in a town where the business has no real presence.
- Dozens of near-identical city pages.
- Phone numbers and hours hardcoded in several templates.
- Heavy map embeds loading on every page.
- Review gating flows.
- Self-serving review markup in the business's own structured data.
- No UTM tag on the profile link, making results impossible to measure.
When to Bring in Local SEO Help
Good local SEO for small business owners doesn't usually need an agency at first. The basics in this guide will put most small service businesses ahead of their local competitors. It's worth bringing in a specialist when the market is very competitive (think personal injury lawyers or HVAC in a big metro area), when the business has several locations, or when it's still invisible after the fundamentals are in place.
Look for someone who starts with an audit, explains what they'll do and why, builds genuine local links rather than buying bulk listings, and never promises a guaranteed spot in the map pack, because Google says there's no way to buy one. A local SEO audit and consultation is a sensible first step before committing to anything ongoing.
FAQs
What is local SEO for a small business?
Local SEO for a small business is the work of helping it appear when people nearby search for its products or services. It covers the Google Business Profile, a website with clear service and location information, consistent business details across the web, reviews and local links. It's especially important for service businesses.
How long does local SEO take to work?
Fixing a Business Profile and basic website issues can show results within weeks, but building strong local rankings usually takes a few months of steady work. Reviews, links and content build up over time, and results depend heavily on how competitive the local market is.
Do I need a website for local SEO?
You can appear in the map results with just a Google Business Profile, but a website helps a lot. It supports relevance and prominence, gives Google more detail about your services, ranks in the local organic results and gives customers a place to learn more and contact you.
Can a service-area business rank without a physical address?
Yes. Service-area businesses can hide their address on their Google Business Profile and list up to 20 service areas, within about two hours' drive of the business. Distance still matters, so rankings are strongest near the business's actual base.
How many location or service-area pages should I create?
Only as many as you can fill with genuinely local, useful content, such as jobs completed in the area, local details and area-specific questions. Google's spam policies warn against near-identical city pages that funnel users to the same place, so a few strong pages beat many thin ones.
Does LocalBusiness schema improve local rankings?
Not directly, as far as Google has said. LocalBusiness structured data helps search engines understand the business's details accurately, and Google says it can help with features like knowledge panels. Map pack rankings depend mainly on relevance, distance and prominence, driven largely by the Business Profile.
How much does local SEO cost?
Many of the basics are free, including setting up a Google Business Profile, fixing website details and asking for reviews. Agencies typically charge a monthly fee that varies widely with competition and scope. In very competitive markets, ongoing professional help can be worth the investment.
Wrapping Up
Local SEO is half Business Profile and half website. On the website side, your job as a developer is clear: build genuinely useful service pages, avoid doorway city pages, keep the business details in one source of truth, generate accurate structured data, make it effortless to call or get directions, and make every click measurable. Do that, and you'll stop getting emails asking why the client isn't on the map, or at least you'll be able to show them exactly why, and what's improving.
Top comments (0)