Agency Tested Local Business Schema with Copy and Paste JSON-LD
Implement JSON-LD LocalBusiness using the most specific @type available, with name, PostalAddress, telephone in E.164 format, and openingHours or openingHoursSpecification as your baseline. Make sure that data matches your verified Google Business Profile exactly, then run it through the Rich Results Test before you publish. That’s the whole job done properly in one afternoon.
TL;DR:
- Using the most specific
@typefor your business helps search engines access features like menus, reservations, and detailed categorization.- Place your JSON-LD schema code in the
<head>section of your website, ensuring it matches your Google Business Profile and is validated with both Rich Results Test and Schema Markup Validator.- For multi-location businesses, create a dedicated schema block for each location with its own contact details and address, rather than a single combined schema on the homepage.
- Regularly audit and update your schema markup, especially after any business hours or address changes, to maintain eligibility for rich results and accurate AI recognition.
Table of Contents
What is local business schema and why does it matter?
Local business schema is a block of code that tells search engines and AI systems exactly who you are, where you are, and when you’re open, in a format machines can read without guessing. Written as JSON-LD, it sits quietly in your page’s <head> and translates the facts on your website into structured data that Google, Bing, and AI assistants like ChatGPT or Perplexity can lift directly and reuse with confidence.
Plain HTML tells a search engine “we’re open Monday to Friday” somewhere in a paragraph. Schema markup tells it precisely, in a format that can be parsed and trusted. That distinction is the whole reason structured data exists. Google Search Central recommends JSON-LD as the preferred structured data format specifically because it’s easier to maintain and less prone to the kind of errors that creep into markup embedded directly in visible page elements.
Getting this right unlocks several real, measurable advantages:
- Eligibility for rich results, including map pack features, business panels, and enhanced listings that plain text can’t trigger.
- Stronger entity signals that connect your website to your Google Business Profile and any Knowledge Panel Google builds for your business.
- Better click-through rates when your listing shows opening hours, ratings, or price range directly in the search result.
- Improved odds of being cited correctly by AI tools that increasingly pull structured facts rather than scraping prose.
Here’s the part most business owners get wrong: they assume more properties always means better results. Google’s own guidance says the opposite. Accuracy beats volume. A handful of correct, consistent fields outperform a bloated schema block with contradictory or half-finished data every time. If your phone number in schema doesn’t match the one on your Google Business Profile, you’ve created a signal that undermines trust rather than building it.
What are the required properties for local business schema?
Google’s LocalBusiness structured data documentation sets out a short list of properties that genuinely matter, and a longer list of recommended extras that strengthen your listing without being strictly mandatory.
The non-negotiables are:
- name: your exact trading name, matching your signage and Google Business Profile.
- address: a structured
PostalAddressobject, never a single free-text string. - telephone: in E.164 international format (e.g. +441273123456), not a locally formatted number.
- openingHours or openingHoursSpecification: your trading hours, in 24-hour format.
The PostalAddress object itself needs its own subfields to parse reliably. Schema confirms that a structured address with distinct fields avoids the geocoding guesswork that a single free-text line forces search engines into.
| Field | Purpose | Example |
|---|---|---|
| streetAddress | Building number and street | 14 High Street |
| addressLocality | Town or city | Lewes |
| addressRegion | County or state | East Sussex |
| postalCode | Postcode | BN7 1XA |
| addressCountry | ISO country code | GB |
Beyond the baseline, several recommended properties genuinely move the needle:
- geo: latitude and longitude, ideally to five or more decimal places for map precision.
- url: your canonical homepage or location page URL.
- image: a representative photo, ideally an array for multiple angles.
- aggregateRating and review: only if you have genuine, verifiable reviews to reference.
- priceRange: a simple indicator like “££” that helps searchers self-select.
- areaServed: the towns or regions you actually cover.
- sameAs: links to your verified social profiles and directory listings.
A few formatting rules trip people up constantly. Country codes must follow ISO 3166-1 alpha-2 (GB, not UK). Times must be 24-hour format (17:00, not 5pm). And skipping postalCode or addressCountry is one of the most common reasons validators flag an address as incomplete, even when the rest of the block looks fine.
Which schema type should you actually use?
Generic LocalBusiness works, but it’s rarely the best choice. Schema.org lists dozens of specific subtypes, and picking the right one unlocks properties that generic LocalBusiness simply doesn’t support.
A restaurant using the Restaurant subtype can add servesCuisine, menu, and acceptsReservations, none of which exist on the generic type. A dentist using Dentist sits correctly within the MedicalBusiness branch of the hierarchy, which can matter for how search engines categorise health-related listings. The logic is simple: the more specific your @type, the more precisely search engines understand what you do, and the more type-specific features become available to you.
Finding the right subtype takes a couple of minutes. Browse the schema.org LocalBusiness page, scroll to “More specific types,” and check which properties each one supports before you commit.
A few common mappings to get you started:
- Restaurant, café, or takeaway →
Restaurant,CafeOrCoffeeShop, orFastFoodRestaurant - Dental or medical practice →
DentistorMedicalBusinesssubtypes - Trades (plumbing, electrical, building) →
Plumber,Electrician,GeneralContractor - Retail shop →
Storeor a relevant subtype likeClothingStore - Legal or accountancy practice →
LegalServiceorAccountingService - Gym or fitness studio →
ExerciseGymorSportsActivityLocation
If none of the subtypes fit your business precisely, generic LocalBusiness is a perfectly acceptable fallback. It’s far better to use it correctly than to force your business into a subtype that doesn’t match what you actually do.
Can you provide an example of schema markup?
Here’s a minimal, valid LocalBusiness block containing only the required properties. Copy it, swap in your own details, and you have a working baseline.
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"name": "Bell & Co Hardware",
"address": {
"@type": "PostalAddress",
"streetAddress": "14 High Street",
"addressLocality": "Lewes",
"addressRegion": "East Sussex",
"postalCode": "BN7 1XA",
"addressCountry": "GB"
},
"telephone": "+441273123456",
"openingHoursSpecification": [
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
"opens": "09:00",
"closes": "17:30"
}
]
}
Now a fuller example, using the Restaurant subtype with geo coordinates and an image array:
{
"@context": "https://schema.org",
"@type": "Restaurant",
"@id": "https://example.co.uk/#organization",
"name": "The Cliffe Bistro",
"url": "https://example.co.uk",
"telephone": "+441273987654",
"image": [
"https://example.co.uk/images/front.jpg",
"https://example.co.uk/images/dining-room.jpg"
],
"address": {
"@type": "PostalAddress",
"streetAddress": "22 Cliffe High Street",
"addressLocality": "Lewes",
"addressRegion": "East Sussex",
"postalCode": "BN7 2AH",
"addressCountry": "GB"
},
"geo": {
"@type": "GeoCoordinates",
"latitude": 50.87389,
"longitude": 0.01234
},
"openingHoursSpecification": [
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Tuesday", "Wednesday", "Thursday"],
"opens": "12:00",
"closes": "22:00"
}
],
"priceRange": "££",
"servesCuisine": "British"
}
A quick field-by-field note. @context always points to https://schema.org and stays identical across every block you write. @type is your chosen subtype. @id is optional but useful for multi-location sites, since it gives search engines a stable anchor to reference. The script itself belongs inside your page’s <head>, wrapped in <script type="application/ld+json"> tags, and every value inside it, especially name, address, and phone number, must match your Google Business Profile character for character.
Pro Tip: Keep one canonical copy of your business details, whether that’s a spreadsheet, a CMS field, or a JSON file, and generate your schema from it. Typing the same address into five different places is exactly how NAP mismatches happen.
Where should you place JSON-LD on different platforms?
Deployment looks different depending on your stack, but the underlying principle never changes: one source of truth, rendered consistently.
Static HTML sites: paste the
<script type="application/ld+json">block directly into the<head>of each relevant page. If you manage multiple pages by hand, keep a single template file for the schema structure and update only the data values, rather than rewriting the block from scratch each time.WordPress: most schema plugins can handle this, but check for a specific capability before you install one: can it emit a separate LocalBusiness block per location page, rather than cramming every branch into a single homepage block? Confirm it can sync fields (address, hours, phone) from a central data source, so you’re not manually editing JSON in five different plugin screens when your hours change for Christmas.
Headless setups (React, Next.js, and similar): render the JSON-LD server-side or inside your head component, so it’s present in the initial HTML response rather than injected late by client-side JavaScript. Store your location data in your CMS as structured fields, then generate the schema block programmatically for each location page. This keeps your visible content and your structured data pulling from the same record, which is exactly what stops the two from drifting apart over time.
Whichever route you take, the test is the same: view your page source, confirm the script tag is present and populated, and check it matches what a visitor actually sees on the page.
How do you handle opening hours and seasonal schedules?
openingHoursSpecification handles complexity that the simpler openingHours string can’t. Once your hours involve overnight spans, seasonal changes, or holiday closures, the specification object becomes the only reliable option.
Schema.org’s OpeningHoursSpecification documentation confirms that times must be written in 24-hour format, and that overnight spans (a bar open until 2am, say) are expressed by setting the closing time on the following calendar boundary.
A few patterns worth having ready:
- Standard hours across several days: use an array for
dayOfWeek(e.g. Monday to Friday) rather than repeating identical blocks five times. - Overnight spans: set
opensto the evening start time andclosesto the early morning time, e.g. opens “18:00”, closes “02:00”. - Full-day closures: add a specification with
opensandclosesboth set to “00:00”, or omit that day from yourdayOfWeekarray entirely. - Seasonal changes: use
validFromandvalidThroughdates to bracket a separate specification object for summer or Christmas hours.
The two mistakes that cause the most validation failures are using 12-hour time formats (5pm instead of 17:00) and letting your schema hours drift out of sync with the hours actually displayed on the page. Search engines and AI tools compare the two, and a mismatch damages trust in both.
How should multi-location and service-area businesses use schema?
The single biggest architecture mistake local businesses make is cramming every branch into one schema block on the homepage. It doesn’t work, and it actively confuses search engines about which address applies to which service.
The correct pattern, backed by consistent practitioner implementation guidance, is one dedicated page per location, each carrying its own complete LocalBusiness block with its own address, phone number, and hours. Your homepage can then carry a parent Organization block, linking out to each location via sameAs or a shared @id reference, so search engines understand the relationship between the parent brand and its branches.

If you’re a service-area business, a mobile plumber or a cleaning company covering several towns without a public shopfront, you can omit streetAddress where genuinely appropriate and rely on areaServed instead. List the specific towns or regions you cover, or use a GeoShape or GeoCircle object for a radius-based service area. Still choose the most specific subtype you can (Plumber, Electrician) rather than defaulting to generic LocalBusiness just because you lack a shopfront.
A few precision points worth locking down:
- Use five or more decimal places on your geo coordinates. Fewer decimal places can place you streets away from your actual location.
- Keep your NAP (name, address, phone number) byte-identical across your schema, your Google Business Profile, and your visible page content. Even a “St” versus “Street” inconsistency creates friction.
- For genuinely separate legal entities trading under one brand, treat each as its own LocalBusiness rather than forcing them under a single umbrella listing.
If your Google Business Profile isn’t fully accurate to start with, schema markup won’t fix that gap. Our guide on boosting your Google Business Profile covers the groundwork worth doing alongside this.
How do you validate schema and fix common errors?
Two tools do this job properly, and you should use both, not just one. Google’s Rich Results Test checks whether your markup qualifies for Google’s specific rich result types. The Schema Markup Validator checks broader vocabulary compliance and nested type correctness, catching issues the Rich Results Test won’t flag because they don’t affect Google’s rich results but still represent invalid schema.
Run both before publishing, and again after any change to your hours, address, or phone number.
The recurring errors worth watching for:
- Missing PostalAddress subfields: usually
postalCodeoraddressCountryleft out, which breaks reliable parsing even when the address looks complete to a human reader. - NAP mismatches: your schema says one phone number, your Google Business Profile says another.
- JSON syntax errors: a missing comma or unclosed bracket invalidates the entire block, not just one field.
- Wrong time formats: 12-hour times where 24-hour format is required.
- Homepage-only multi-location blocks: one LocalBusiness block trying to represent five branches.
Statistic Callout: Google’s own structured data guidance stresses that a smaller set of accurate, complete properties outperforms a large set of partially filled ones that risk contradicting each other. Precision beats coverage every time.
Set a cadence rather than treating this as a one-off task. A quarterly check, plus an immediate re-validation any time your hours or address change, catches drift before it costs you a rich result.
MB Web’s practical schema checklist
We’ve been building and maintaining websites from Lewes for 50 years, and schema markup is one of those jobs that looks simple until you’re three locations deep and nobody remembers which spreadsheet has the correct opening hours. Here’s the checklist we actually work through with clients.
- Audit existing markup first. Half the sites we look at already have schema, and half of those have errors nobody’s noticed.
- Confirm NAP consistency across the website, Google Business Profile, and any directory listings before touching the code.
- Implement the most specific
@typeavailable, not generic LocalBusiness by default. - Build one location page per branch for multi-location clients, never a single homepage block trying to cover everyone.
- Validate with both the Rich Results Test and Schema Markup Validator before anything goes live.
- Set a quarterly review, plus an immediate check whenever hours, address, or phone details change.
The most common issues we fix aren’t exotic. They’re stale opening hours from a bank holiday six months ago, phone numbers that don’t match Google Business Profile, and multi-location businesses that never separated their branches into individual schema blocks in the first place. None of it is difficult once someone actually looks.
When should you DIY schema and when should you hire an agency?
Honestly, plenty of this is well within reach for a competent site owner. Editing a JSON-LD block to update your opening hours, running a validation check, or correcting a single address field are all tasks you can handle yourself with a text editor and twenty minutes.
Where it gets genuinely harder is anything involving scale or architecture. Rolling out consistent schema across a dozen locations, wiring up a headless React or Next.js build so the markup renders server-side, or coordinating your schema data with a Google Business Profile sync across multiple branches, that’s where DIY attempts tend to go wrong quietly, without anyone noticing until a rich result disappears.
If you do bring in an agency, brief them properly with a clear SEO audit service before any implementation work starts. Ask for a written audit before any implementation work starts, a clear list of which @type they’re recommending and why, and a validation report showing both Rich Results Test and Schema Markup Validator passes before sign-off. Any agency worth paying will give you that without being asked twice.
— James Golding
Get your schema audited properly, without the sales pressure
We offer a practical alternative to guessing your way through JSON-LD or hoping a plugin’s default settings are doing the job right. We offer straightforward schema audits, hands-on JSON-LD implementation, and multi-location rollouts built on the same principles covered here, no long-term lock-in, just clear scoped work with a defined deliverable.
The first step is simple: get in touch, tell us what you’re working with, and we’ll scope an honest brief covering what needs fixing and what’s already fine. We don’t pad out work that isn’t needed, that’s the whole point of being upfront about this. If your build needs deeper technical work, our website development team can handle headless or custom CMS setups, and if you want the schema work folded into a broader local visibility push, our SEO services cover technical audits and ongoing monitoring too. Drop us a line and let’s talk about what your site actually needs.
Sources
Before you publish anything, run it past the sources that actually govern how this markup gets interpreted.
Bookmark these four. Between them, they’ll catch almost every issue before it costs you a rich result.
FAQ
Can you explain schema markup in a simple way?
Schema markup is a small block of code added to your website that describes your business in a format search engines and AI tools can read directly, rather than having to guess from your page’s visible text.
Can you provide an example of schema markup?
A minimal example includes your business name, a structured address, your phone number in international format, and your opening hours, all written in JSON-LD and placed in your page’s <head>. See the full copy-paste examples above for both a basic and a restaurant-specific version.
What is a local business schema?
Local business schema is a specific type of structured data, based on the schema.org LocalBusiness type, used to describe a physical or service-area business including its name, address, contact details, and trading hours.
Can you give me an example of a Local Business schema?
Yes. A basic block includes name, a PostalAddress object, telephone, and openingHoursSpecification, wrapped in @context and @type declarations and written as JSON-LD in your page’s head section, exactly as shown in the examples earlier in this guide.