Structured Data for Local SEO: A Practical 2026 Guide

Local SEO structured data is JSON-LD markup that tells Google what your business is, where it is, and what it does. Use the most specific LocalBusiness subtype that fits, like Plumber or Dentist, keep your name, address, and phone identical everywhere, and validate it with Google's Rich Results Test.
Part of the complete SEO guide.
On this page
- What structured data does for a local business
- Pick the right type: LocalBusiness and its subtypes
- A complete, correct LocalBusiness example
- Connect it to your Google Business Profile
- Reviews, FAQ, and breadcrumbs
- Service pages and the @id pattern
- Mistakes that quietly hurt you
- How to validate and monitor
- FAQ
- Do I need structured data if I already have a Google Business Profile?
- Will structured data alone improve my local rankings?
- Should I use a plugin or hand-code the JSON-LD?
Most local businesses either have no structured data at all or have it copy-pasted from a plugin that spits out the wrong schema type. Both cases cost you visibility in the local pack and in AI-generated answers. Here is what actually matters in 2026, with the markup I use on client sites.
What structured data does for a local business
Structured data is machine-readable code on your page that tells search engines what your business is, where it is, and what it does. Google uses it for rich results, but the bigger shift since 2024 is that AI answer engines (Google’s AI Overviews, Bing Copilot, ChatGPT search) lean on it heavily to decide which business to name when someone asks “best plumber near Commack.” If your data is missing or contradictory, you get skipped. It’s that simple.
Schema.org vocabulary is the standard, and Google’s Rich Results Test is the validator. Everything below is JSON-LD, which is what Google recommends and what is easiest to maintain.
Pick the right type: LocalBusiness and its subtypes
The most common mistake I see is using the generic LocalBusiness type for everything. Google supports dozens of specific subtypes, and using the correct one helps matching. A few examples:
Plumber,Electrician,HVACBusiness,RoofingContractorfor tradesRestaurant,CafeOrCoffeeShop,Bakeryfor foodDentist,Physician,MedicalClinicfor healthLegalServiceorAttorneyfor law firmsHomeAndConstructionBusinessas a fallback for general contractors
If you truly fit none of them, plain LocalBusiness is fine. Do not stack three conflicting types on one page.
A complete, correct LocalBusiness example
Here is a realistic block for a service-area business. Note the nested PostalAddress, the areaServed list, and geo. Coordinates should be the actual centroid of your service area or your shop, not a random nearby town.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Plumber",
"@id": "https://example.com/#business",
"name": "Riverhead Plumbing Co.",
"url": "https://example.com/",
"telephone": "+1-631-555-0142",
"priceRange": "$$",
"image": "https://example.com/img/storefront.jpg",
"address": {
"@type": "PostalAddress",
"streetAddress": "412 Main St",
"addressLocality": "Riverhead",
"addressRegion": "NY",
"postalCode": "11901",
"addressCountry": "US"
},
"geo": {
"@type": "GeoCoordinates",
"latitude": 40.9170,
"longitude": -72.6620
},
"areaServed": [
{ "@type": "City", "name": "Riverhead" },
{ "@type": "City", "name": "Commack" },
{ "@type": "AdministrativeArea", "name": "Suffolk County" }
],
"openingHoursSpecification": [
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
"opens": "08:00",
"closes": "17:00"
}
],
"sameAs": [
"https://www.google.com/maps/place/?q=place_id:YOUR_PLACE_ID",
"https://www.facebook.com/riverheadplumbing"
]
}
</script>
Three things worth calling out. First, @id gives the entity a stable identifier so other pages can reference it instead of repeating the whole block. Second, sameAs should include your Google Business Profile. Third, openingHoursSpecification uses 24-hour time and must match your GBP hours exactly. Mismatches cause Google to distrust the whole entity.
Connect it to your Google Business Profile
Your website schema and your GBP are two records of the same business. Google cross-references them. If your site says the business is in Smithtown and your GBP says Hauppauge, that conflict is a real ranking problem, not a cosmetic one.
- Name, address, and phone must match character for character (this is your NAP consistency)
- Include the GBP URL in
sameAsand, if you have it, theplace_id - Keep hours, categories, and service areas aligned
- Link your GBP website field to the canonical homepage, not a tracking URL
If you’re also doing the on-page work, this dovetails with the basics covered in my Long Island SEO breakdown.
Reviews, FAQ, and breadcrumbs
Two of these are still worth your time in 2026. One is not.
- Reviews: Google no longer shows star rich results for self-serving
RevieworAggregateRatingmarkup on your own LocalBusiness when the reviews are about you. You can still mark up reviews you collect on your own site, and it helps AI engines understand sentiment, but do not expect stars in the SERP. - FAQPage: Google restricted FAQ rich results to authoritative health and government sites in 2023. The markup is still valid and AI answer engines do read it, so it’s worth keeping for question-and-answer content. Just don’t count on the visual result.
- BreadcrumbList: Low effort, still shows in results, and clarifies your site structure. Do it.
Service pages and the @id pattern
If you have separate pages per service and per town, don’t dump a full LocalBusiness block on every page. Put the full block once on the homepage with an @id, then reference it from service pages. Here’s a lightweight Service block that points back to the main entity:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Service",
"serviceType": "Emergency Drain Cleaning",
"provider": { "@id": "https://example.com/#business" },
"areaServed": {
"@type": "City",
"name": "Commack"
},
"url": "https://example.com/services/drain-cleaning-commack/"
}
</script>
The provider reference resolves to the homepage entity. This keeps your data consistent and makes it obvious to search engines that all these pages belong to one business.
Mistakes that quietly hurt you
- Marking up a fake address or a virtual office you don’t actually operate from
- Using
Organizationwhen you should useLocalBusinessor a subtype - Duplicate
LocalBusinessblocks with different phone numbers across pages - Hardcoding hours that changed two years ago
- Stuffing every town in the state into
areaServedto game proximity (it doesn’t work and can read as spam) - Forgetting to re-test after a theme update wipes your
<head>injection
That last one is the most common. If you’re on a heavily customized theme, it’s worth wiring schema into the templates properly rather than through a plugin, which is the kind of thing that comes up in custom web development work.
How to validate and monitor
- Run every key page through Google’s Rich Results Test and the Schema Markup Validator
- Check Search Console’s Enhancements reports monthly for new errors
- Keep a plain-text copy of your schema in your repo so theme updates don’t erase it
- Re-verify after any GBP change (hours, address, category)
FAQ
Do I need structured data if I already have a Google Business Profile?
Yes. The GBP is Google’s own record, but your website schema is what other search engines and AI answer tools read. They reinforce each other, and mismatches between them cause problems.
Will structured data alone improve my local rankings?
No. It’s a clarity signal, not a ranking lever on its own. It helps you appear in rich results and AI answers, but rankings still depend on relevance, proximity, reviews, and links.
Should I use a plugin or hand-code the JSON-LD?
For a simple brochure site, a reputable plugin is fine if you verify its output. For anything with multiple services, locations, or a custom theme, hand-coding gives you control and prevents the plugin from overwriting your data on updates.


