Fill in the properties below and this markup can earn the Local business listing in Google Search.
Without these, the markup is not valid.
Use the name on your signage and on your Google Business Profile, character for character.
Valid without them, but you lose eligibility or detail.
Pick the most specific type that is still true. schema.org has dozens more subtypes; these five cover most businesses.
Include the country code. Use the same number as your Google Business Profile.
A symbol range such as $$ or a plain band such as 50 to 200 USD. Google lists priceRange as a recommended property and takes it as free text, so keep it short.
A real photo of the premises works better than a logo. Google does not list image among LocalBusiness's properties; the image guidance it does publish, for the restaurant carousel, asks for crawlable, indexable images of at least 50,000 pixels multiplying width by height.
2 errors must be fixed before this markup will validate.
{
"@context": "https://schema.org",
"@type": "LocalBusiness"
}LocalBusiness markup describes a business that customers can visit at a physical address. It carries the name, address, telephone number, opening hours and price range a search engine needs to place you on a map and to answer a question like whether you are open right now. Google still supports this one, so unlike FAQ markup it earns something visible. Two things are true here at once, and most advice gives you only one of them. This markup will not create, claim or edit your Google Business Profile, and on its own it will not put you in the local pack: if you are adding schema in order to rank in the map results, you are solving the wrong problem. Separately, it is genuinely worth adding, because markup that agrees with your profile reinforces the association between the site and the business, can fill gaps where a profile is unclaimed or thin, and states your location, hours and contact details in valid schema.org that any consumer is free to parse. You will also read that this markup feeds AI answer engines: no vendor publishes whether it does, so treat that as an assumption rather than a reason. Consistency is the condition on all of it. If your site says one phone number and your profile says another, you have given Google a reason to trust neither.
Tier reflects what Google actually documents for LocalBusiness, not a guess at what looks thorough.
| Property | Tier | What it does |
|---|---|---|
| name | Required | The trading name, matching your signage and your Google Business Profile. |
| @type | Recommended | A specific subtype such as Restaurant, Store or ProfessionalService. The generic LocalBusiness is valid but tells Google less. |
| address | Required | A PostalAddress node. A string address parses but throws away the structure that makes it useful. |
| address.streetAddress | Required | Street number and name, on one line. Google does not itemise which address sub-properties are required, only that address itself is, and asks for as many sub-properties as possible. Marked required here because an address with no street number is not usable. |
| address.addressLocality | Required | City or town. Not individually required by Google, for the same reason as street address above. Marked required here because Google needs a city to place the business. |
| address.addressRegion | Recommended | State, province or region. Skip it only where the country has no such level. |
| address.postalCode | Required | Postal or ZIP code. The most precise part of the address. Not individually required by Google, for the same reason as street address above. |
| address.addressCountry | Required | Two-letter ISO 3166-1 country code, not the country name. Not individually required by Google, for the same reason as street address above. |
| telephone | Recommended | Include the country code. This is what powers click-to-call on mobile. |
| url | Recommended | The canonical URL for this location, not the site home page if the two differ. |
| image | Optional | A photo of the premises. Not listed in Google's LocalBusiness property table at all; the image guidance it does publish, for the restaurant carousel, asks for at least 50,000 pixels multiplying width by height. |
| openingHoursSpecification | Recommended | An array of OpeningHoursSpecification nodes, one per day. Days you omit read as closed. |
| openingHoursSpecification.dayOfWeek | Required | The day this row covers, spelled out in English. |
| openingHoursSpecification.opens | Required | Google documents hh:mm:ss, for example 09:00:00, and hh:mm is accepted too. Never 9am. |
| openingHoursSpecification.closes | Required | Google documents hh:mm:ss, and hh:mm is accepted too. Use 23:59:59 for a business that closes at midnight. |
| priceRange | Recommended | A free-text indication of price level, such as $$. Recommended by Google. |
| geo | Recommended | A GeoCoordinates node. Recommended by Google, and most valuable where a geocoder would struggle to find your entrance. |
| geo.latitude | Required | Required once you add a geo node at all. Decimal degrees, not degrees and minutes. |
| geo.longitude | Required | Required once you add a geo node at all. Negative west of Greenwich. |
A single-location coffee shop, open six days a week, with a storefront photo.
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"name": "Ravenswood Coffee Roasters",
"url": "https://ravenswoodcoffee.example",
"telephone": "+1 312 555 0142",
"image": "https://ravenswoodcoffee.example/images/storefront.jpg",
"priceRange": "$$",
"address": {
"@type": "PostalAddress",
"streetAddress": "4650 N Damen Ave",
"addressLocality": "Chicago",
"addressRegion": "IL",
"postalCode": "60640",
"addressCountry": "US"
},
"geo": {
"@type": "GeoCoordinates",
"latitude": 41.9689,
"longitude": -87.674
},
"openingHoursSpecification": [
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": "Monday",
"opens": "07:00:00",
"closes": "18:00:00"
},
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": "Tuesday",
"opens": "07:00:00",
"closes": "18:00:00"
},
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": "Wednesday",
"opens": "07:00:00",
"closes": "18:00:00"
},
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": "Thursday",
"opens": "07:00:00",
"closes": "18:00:00"
},
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": "Friday",
"opens": "07:00:00",
"closes": "19:00:00"
},
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": "Saturday",
"opens": "08:00:00",
"closes": "19:00:00"
}
]
}Two things to notice. The address is a nested PostalAddress node rather than one string, which is what lets Google match it against the address on your Business Profile. And openingHoursSpecification is an array with one entry per day: Sunday is absent because the shop is closed, and there is no separate closed flag to set.
The three-result map pack is drawn from Google Business Profile data, not from your website's structured data, so this markup will not rank you there and cannot substitute for claiming your profile. The value it does have is a separate thing: markup that agrees with your profile reinforces the association between the site and the business, helps Google fill gaps where a profile is unclaimed or thin, and states your location in valid schema.org that any consumer is free to parse. Add it for that. Claim the profile for the map pack.
Much of the value of this markup is confirming that the entity on your site is the entity in the profile. A different suite number, an old phone number, or Ltd on one and Limited on the other weakens the match rather than strengthening it. Copy the profile exactly.
LocalBusiness asserts a physical location open to the public. A plumber who works at customer sites, or an agency that operates from a home office, should use Organization instead, or LocalBusiness with areaServed and no storefront claim. Publishing a street address customers cannot visit is the version of this that earns a complaint.
Each location needs its own node, on its own page, with its own address, phone number and hours. Site-wide markup for one branch tells Google the wrong thing about every other page it appears on.
Google documents opens and closes in hh:mm:ss form, so 09:00:00, and hh:mm works too. 9am, 9.00 and 9:00 AM are all invalid, and a JSON validator will pass the document while Google makes nothing of the hours. Use 23:59:59 rather than 24:00:00 for a midnight close.
Google's LocalBusiness guidance says aggregateRating and review are only recommended for sites that capture reviews about other local businesses. A rating you publish about yourself, on your own site, is not what those properties are for.
Paste the script tag into the page for that location, inside <head> or anywhere in <body>. On a single-location site the contact or home page is the right host; on a multi-location site each location page carries its own tag.
Check first whether your SEO plugin already emits LocalBusiness markup. Yoast Local SEO and Rank Math both can, and two competing LocalBusiness nodes on one page is worse than one. If nothing is emitting it, paste the tag into a Custom HTML block on the location page, or hook it into wp_head with a conditional for that page ID.
Add the tag to templates/page.contact.liquid, or to theme.liquid inside a conditional on the page handle so it fires on the contact page only. Do not put it in theme.liquid unconditionally: that would claim every product and collection page is the storefront.
Want this markup built into your site and kept correct as it changes, rather than pasted in by hand? See how we handle that.
Get a free audit of your site's technical SEO, structured data and performance.