Local Business Schema Markup: A Practical JSON-LD Guide
How to write LocalBusiness structured data that validates, matches your Google Business Profile and scales to many locations, with copy-ready JSON-LD.
Local Business Schema Markup: A Practical JSON-LD Guide
Local business schema is structured data that describes a physical business to search engines: its name, address, phone number, opening hours, location on a map and the kind of business it is. Written in JSON-LD, it takes an hour to implement properly and removes a lot of guesswork from how Google understands your locations.
This guide covers what the markup does and does not do, the properties that matter, complete examples you can adapt, and the mistakes that cause markup to be ignored.
What local business schema does (and does not do)
LocalBusiness is a schema.org type, with many more specific subtypes. Google documents support for it in its structured data guidelines and may use it to show business details in Search and Maps, such as hours, address and phone number.
Set expectations correctly:
- It helps Google understand and confirm facts about your business, particularly when your website and your Google Business Profile agree.
- It is not a direct ranking boost. Structured data makes pages eligible for certain features; it does not move a page up the results by itself.
- It does not replace Google Business Profile. The local pack and Maps rely primarily on your Business Profile, its categories, reviews and proximity to the searcher. Schema on your site supports that profile; it does not substitute for it.
- It does not guarantee any rich result. Google decides whether and how to show structured data.
The practical value is consistency. When the name, address and phone number on your site, in your markup and on your Business Profile match exactly, you remove ambiguity, which matters most for businesses with similar names, multiple locations or a recent move.
Choose the most specific type
Do not stop at LocalBusiness if a more specific subtype exists. schema.org has hundreds of them. Some common ones:
| Business | Schema type |
|---|---|
| Dental practice | Dentist |
| Restaurant | Restaurant (with servesCuisine) |
| Café | CafeOrCoffeeShop |
| Plumber | Plumber |
| Electrician | Electrician |
| Law firm | LegalService or Attorney |
| Hair salon | HairSalon |
| Car repair shop | AutoRepair |
| Hotel | Hotel |
| Gym | ExerciseGym |
| Real estate agency | RealEstateAgent |
| Medical clinic | MedicalClinic |
Every subtype inherits all LocalBusiness properties, so there is no downside to being specific. If nothing fits, use LocalBusiness and describe the business in description.
Required and recommended properties
Google's documentation lists name and address as required. In practice, a useful implementation includes more:
| Property | Status | Notes |
|---|---|---|
name | Required | Exactly as on your Business Profile and signage. No keyword stuffing. |
address | Required | A PostalAddress with street, locality, region, postal code and country. |
telephone | Recommended | Include the country code, for example +1-512-555-0142. |
url | Recommended | The URL of this specific location's page. |
geo | Recommended | GeoCoordinates with latitude and longitude, at least five decimal places. |
openingHoursSpecification | Recommended | One entry per set of days with identical hours. |
priceRange | Recommended | A short indicator such as $$, or a range like $20-$60. |
image | Recommended | Real photos of the location, crawlable, not a logo only. |
servesCuisine, menu | Recommended for food | Restaurants and cafés. |
department | Optional | For a business with distinct departments, like a pharmacy inside a store. |
sameAs | Optional | Official profiles: Business Profile share link, Facebook, LinkedIn, Yelp. |
A complete single-location example
This is a full, realistic block for a dental practice. Place it in the head or body of the location's page:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Dentist",
"@id": "https://www.example-dental.com/#practice",
"name": "Riverside Family Dental",
"url": "https://www.example-dental.com/",
"telephone": "+1-512-555-0142",
"image": [
"https://www.example-dental.com/images/reception-1x1.jpg",
"https://www.example-dental.com/images/reception-4x3.jpg",
"https://www.example-dental.com/images/reception-16x9.jpg"
],
"priceRange": "$$",
"address": {
"@type": "PostalAddress",
"streetAddress": "1200 Riverside Dr, Suite 210",
"addressLocality": "Austin",
"addressRegion": "TX",
"postalCode": "78704",
"addressCountry": "US"
},
"geo": {
"@type": "GeoCoordinates",
"latitude": 30.24512,
"longitude": -97.74631
},
"openingHoursSpecification": [
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday"],
"opens": "08:00",
"closes": "17:30"
},
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": "Friday",
"opens": "08:00",
"closes": "13:00"
}
],
"sameAs": [
"https://www.facebook.com/example-dental",
"https://www.linkedin.com/company/example-dental"
]
}
</script>
A few details worth noting:
- Closed days are simply omitted. Saturday and Sunday do not appear, which means closed.
- Times use 24-hour
hh:mmformat in the business's local time. - The
@idgives this entity a stable identifier you can reference from other markup on the site, such as anOrganizationblock or aService.
Special opening hours
For a business open around the clock, use "opens": "00:00" and "closes": "23:59". For holiday closures or seasonal hours, add an entry with validFrom and validThrough:
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
"opens": "00:00",
"closes": "00:00",
"validFrom": "2026-12-24",
"validThrough": "2026-12-26"
}
Setting opens and closes both to 00:00 within a date range marks the business closed for those dates. Update your Business Profile's special hours at the same time; Google treats the profile as the primary source for hours.
Multiple locations
The most common structural error on multi-location sites is putting every location's markup on the homepage. Instead:
- Create one page per location, with its own URL, address, phone number, hours, map and photos.
- Put a single
LocalBusinessblock on each location page, describing only that location. - Mark up the brand once as an
Organizationon the homepage or about page, and connect each location to it withparentOrganization.
{
"@context": "https://schema.org",
"@type": "AutoRepair",
"@id": "https://www.example-auto.com/locations/denver/#location",
"name": "Example Auto Care Denver",
"url": "https://www.example-auto.com/locations/denver/",
"telephone": "+1-303-555-0188",
"parentOrganization": {
"@id": "https://www.example-auto.com/#organization"
},
"address": {
"@type": "PostalAddress",
"streetAddress": "455 Colfax Ave",
"addressLocality": "Denver",
"addressRegion": "CO",
"postalCode": "80203",
"addressCountry": "US"
}
}
Link the location pages from a crawlable store locator with plain HTML links, not only from a JavaScript map widget. Our internal linking strategy guide covers how to structure location hubs so each page gets discovered and receives internal authority.
Service-area businesses
Plumbers, cleaners and mobile mechanics often have no storefront customers visit. You can still use a LocalBusiness subtype. Two points:
- If your Business Profile hides your address, keep your markup consistent with what you show publicly. Do not publish a home address in markup that you hide elsewhere.
- schema.org's
areaServedproperty lets you describe the cities or regions you cover. Google's local business documentation does not list it as a property it uses, so treat it as descriptive context rather than something that will change how you appear.
"areaServed": [
{ "@type": "City", "name": "Austin" },
{ "@type": "City", "name": "Round Rock" },
{ "@type": "City", "name": "Cedar Park" }
]
Testing and validation
Use two tools, because they answer different questions:
| Tool | Answers | Use it for |
|---|---|---|
| Google Rich Results Test | Does Google parse this and is it eligible for a Google feature? | Checking Google-specific requirements and seeing the rendered page |
| Schema Markup Validator (validator.schema.org) | Is this valid schema.org vocabulary? | Catching typos, wrong types and properties that do not exist |
After deploying, check the Enhancements section of Search Console for any structured data reports that apply to your page types, and use URL Inspection on a location page to confirm Google sees the markup in the rendered HTML. If your markup is injected with JavaScript, rendering matters: see how Googlebot renders JavaScript.
Common mistakes
- NAP mismatch. "Suite 210" in markup, "Ste. 210" on the page and "#210" on the Business Profile. Pick one format and use it everywhere.
- Keyword-stuffed names.
"name": "Riverside Family Dental Best Dentist Austin TX"violates Google's guidelines for Business Profiles and undermines trust in your markup. - Markup that does not match visible content. Hours, prices or ratings in JSON-LD that a visitor cannot see on the page. Google's guidelines require the markup to represent the page's content.
- Every location on one page. It forces Google to guess which entity the page is about.
- Stale hours. Markup copied once from an old template and never updated after hours changed. Generate it from the same data source as the visible hours.
- Plugin conflicts. On WordPress, an SEO plugin and a theme both outputting a
LocalBusinessblock with different data. Our WordPress SEO audit checklist covers how to spot duplicate schema output.
A maintenance routine
Structured data breaks quietly. A theme update, a CMS migration or a new location page built from an old template can remove or corrupt it without any visible change.
- Re-run the Rich Results Test on one page per template after every release that touches templates.
- Review structured data reports in Search Console monthly.
- Audit NAP consistency across your site and Business Profile whenever a location moves, changes phone numbers or changes hours.
Structured data is one item on a much longer list. For the rest, the technical SEO audit checklist walks through crawlability, indexing and performance. If you want a professional review of all of it, see our fixed-price audit options.
Summary
- Local business schema describes your business in JSON-LD; it supports your Google Business Profile but does not replace it or directly boost rankings.
- Use the most specific
LocalBusinesssubtype and always includenameandaddress, plus phone, URL, geo coordinates, hours and images. - On multi-location sites, give every location its own page and its own markup, linked to one
Organization. - Keep name, address and phone identical across markup, visible content and your Business Profile.
- Validate with both the Rich Results Test and the Schema Markup Validator, and recheck after every template change.
Get Your SEO Audit
Every issue in this article, checked on your site by an auditor and delivered as a prioritized roadmap within 48-72 hours.
See pricing