Local business schema markup is one of the few local SEO tasks with a right answer. Either the JSON-LD parses, the properties match reality, and the values agree with your Google Business Profile — or they do not. There is no judgment call, which makes it the fastest technical win available to most local sites.
It is also routinely done badly: wrong type, missing address fields, hours in the wrong format, and a phone number that contradicts every other source. Here is how to do it correctly.
Pick the Most Specific Subtype
Schema.org defines LocalBusiness as a broad type with a deep hierarchy of subtypes beneath it. Using the specific one communicates more than the generic one.
- Medical and health:
Dentist,Physician,MedicalClinic,Optician,Pharmacy,VeterinaryCare - Home services:
Plumber,Electrician,HVACBusiness,RoofingContractor,MovingCompany,Locksmith - Professional:
LegalService,Attorney,AccountingService,InsuranceAgency,RealEstateAgent - Food and retail:
Restaurant,CafeOrCoffeeShop,Bakery,ClothingStore,AutoRepair
Check the schema.org type list rather than guessing at names. Types are case-sensitive and exact, and a near-miss like “HVACContractor” instead of the correct “HVACBusiness” is silently discarded — no error, no warning, no benefit. Two minutes verifying the string saves months of markup doing nothing.
If nothing fits, fall back to LocalBusiness itself — do not invent a type, because unrecognized types are simply ignored. Where a business genuinely spans two categories, you can supply an array for @type, though in practice one accurate primary type plus a good description serves better.
Required vs Recommended Properties
Google’s structured data documentation distinguishes what it needs from what it can use. Treat the first group as mandatory.
Required in practice: name, address (as a nested PostalAddress with streetAddress, addressLocality, addressRegion, postalCode, and addressCountry), and telephone. Without a complete address, the markup describes an entity that cannot be placed.
Strongly recommended: url, image, geo (with latitude and longitude), openingHoursSpecification, priceRange, and sameAs pointing at your verified profiles on other platforms. For businesses that serve customers at their location rather than a storefront, add areaServed.
Situational: menu for restaurants, servesCuisine, department for businesses with distinct in-store units, and aggregateRating — but only where the ratings are genuinely collected and displayed on that page. Self-serving review markup that Google cannot corroborate is a manual action risk, not a shortcut to stars.
A Minimal Correct Example
Put JSON-LD in a <script type="application/ld+json"> block. Microdata still works but is harder to maintain and easier to break during template edits, because it entangles the data with the presentation markup. JSON-LD sits in one place and can be regenerated wholesale.
Place it in the <head> or the <body> — Google accepts either. What matters more is that it renders for a crawler that may not execute your JavaScript. Markup injected client-side by a tag manager works less reliably than markup served in the initial HTML response, so prefer server-rendered output where you can control it.
{
"@context": "https://schema.org",
"@type": "Plumber",
"name": "Riverside Plumbing",
"url": "https://example.com/locations/portland/",
"telephone": "+1-503-555-0134",
"priceRange": "$$",
"image": "https://example.com/img/portland-storefront.jpg",
"address": {
"@type": "PostalAddress",
"streetAddress": "412 Oak Street, Suite 200",
"addressLocality": "Portland",
"addressRegion": "OR",
"postalCode": "97204",
"addressCountry": "US"
},
"geo": {
"@type": "GeoCoordinates",
"latitude": 45.5202,
"longitude": -122.6742
},
"openingHoursSpecification": [{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
"opens": "07:00",
"closes": "18:00"
}],
"sameAs": [
"https://www.facebook.com/riversideplumbing",
"https://www.yelp.com/biz/riverside-plumbing-portland"
]
}
Hours, Phone Numbers, and Formatting Rules That Trip People Up
Times use 24-hour HH:MM format. A business open past midnight closes at 23:59 on one specification and opens at 00:00 on the next — not 25:00. A 24-hour operation sets opens and closes both to 00:00.
Phone numbers should be in international format with the country code. Critically, use your real published number, not a call-tracking number that appears nowhere else. Dynamic number insertion that rewrites the number in your markup creates a direct contradiction with your business profile and every citation you have built.
Closures for holidays go in a separate OpeningHoursSpecification entry with validFrom and validThrough dates. Most sites skip this and then confuse users on Thanksgiving.
Consistency With Your Google Business Profile Is the Point
Schema markup for local business pages does not rank you on its own. What it does is corroborate the entity — and corroboration only works when the sources agree.
Every value in your markup should match your Google Business Profile character for character: same legal name without appended keywords, same suite abbreviation, same phone, same hours. Then match that against your site footer, your contact page, and your core citations. A mismatch is worse than an omission, because it introduces doubt where there was none.
For multi-location businesses, generate the markup from your CMS location records rather than hand-writing it per page. Hand-written markup across forty locations drifts within one quarter, and nobody notices until an audit.
Validate With the Rich Results Test, Not the Retired Tool
Google retired the Structured Data Testing Tool. Guides that still tell you to use it are out of date, and so is most of their surrounding advice.
- Rich Results Test — the primary check. It tells you whether Google can parse your markup and whether the page is eligible for any rich result. Test the live URL, not a code paste, so you catch rendering problems.
- Schema Markup Validator (hosted by schema.org) — for general schema.org conformance beyond what Google specifically consumes. Useful when you use properties Google ignores.
- Search Console’s Enhancements reports — the only view of validation at scale across your whole site. Errors here reflect what Google actually saw on crawl, which is the version that matters.
Re-validate after every template change. The most common regression is a CMS update that escapes quotes inside the JSON-LD block and silently breaks parsing on every page at once. Nothing visible changes on the rendered page, which is exactly why it goes unnoticed for months.
A second frequent failure is a plugin adding its own LocalBusiness block alongside yours, leaving two contradictory descriptions of the same entity on one page. View the page source and search for ld+json to count how many blocks are actually being output; on WordPress sites running an SEO plugin plus a theme with built-in schema, two or three is common.
What to Expect After Implementing
Be realistic. Correct markup does not move organic positions directly. What it does is make you eligible for rich features, help disambiguate your entity, and remove a category of technical doubt. Businesses that jump after implementing markup usually jumped because the audit that produced the markup also fixed titles, headings, and internal links.
Recrawling takes days to weeks. Check Search Console rather than refreshing the SERP. And remember that daily rank movement of two or three positions is normal noise — do not attribute it to your markup.
Treat markup as maintenance rather than a project. Hours change, you add a location, a phone number gets ported, someone rebuilds the contact page. Any of those can leave your structured data describing a business that no longer exists in that form, and stale markup is worse than none because it actively contradicts your other sources. Put a quarterly check on the calendar alongside your listings audit.
Fitting This Into a Wider Local Program
Schema is one line item on a longer list that includes profile completeness, NAP consistency, citations, review velocity, and local links. For the profile, citation, map-pack tracking, and review side, use a dedicated local platform — BrightLocal, Whitespark, Yext, or Moz Local. Those are genuinely different products and nothing general replaces them.
For the website side, SEO Rocket covers it at a flat US$50/month: deep technical crawls verified past 900 pages that surface the actual titles, URLs, and H1 text behind each issue, keyword research on country-specific indexes for local intent, an AI writer with hard validation gates for location pages, and top-100 organic rank tracking with Search Console and GA4 connected as ground truth. It has no map-pack tracking, no profile management, and no citation tools — so pair it with a local platform rather than expecting one tool to cover both systems.