/ โ† Local SEO Fixes / LocalBusiness Schema
In this guide
  1. What counts as a schema gap
  2. Choosing the right type
  3. A complete block for a single location
  4. Opening hours that parse, including the awkward ones
  5. Connecting the block to everything else: @id, url and sameAs
  6. Where the markup comes from on common platforms
  7. Validator messages and what they usually mean
  8. The fix, step by step
  9. Keeping it right after today
  10. Questions and answers

What counts as a schema gap

A gap is any difference between what your business really is and what the structured data says it is. The block might be missing altogether, or it might exist but be too vague to be useful. The Local SEO Checker reports LocalBusiness schema completeness, and the gaps it surfaces tend to fall into a handful of patterns.

GapWhat you typically see in the codeWhy it matters
No local markup at allOnly a WebSite or Organization block from the theme.Nothing on the site states an address or opening times in structured form.
Generic type"@type": "LocalBusiness" for a dentist, garage or cafรฉ.A specific type says what you do; the generic one only says you are local.
Partial addressA town and nothing else, or the whole address crammed into streetAddress.Search engines cannot reliably match a partial or merged address to a map location.
No hours, or hours as prose"openingHours": "Mon-Fri 9-5 ish"Free text does not parse, so the hours are ignored.
No coordinatesNo geo block, or coordinates rounded to two decimal places.A rounded point can sit a kilometre away from the door.
Isolated entityNo @id, no sameAs, no url.Nothing links this block to your Business Profile, social profiles or other pages.
Contradicts the pageMarkup phone number differs from the one in the header.Structured data that disagrees with visible content is treated with suspicion.

Google's documentation for local business structured data lists name and address as required, and recommends fields including telephone, url, geo, openingHoursSpecification, priceRange and department. None of this guarantees a special search feature. What the markup does is remove ambiguity about basic facts, and ambiguity is exactly what local search punishes.

Choosing the right type

Schema.org has a long tree of types beneath LocalBusiness. Pick the deepest one that is honestly true. If nothing fits exactly, go one level up rather than picking something close but wrong.

BusinessGood typeNotes
Dental practiceDentistSits under both MedicalBusiness and LocalBusiness.
Plumber, electrician, rooferPlumber, Electrician, RoofingContractorAll under HomeAndConstructionBusiness.
Garage or MOT centreAutoRepairUnder AutomotiveBusiness.
Cafรฉ, restaurant, takeawayCafeOrCoffeeShop, Restaurant, FastFoodRestaurantFood types also accept servesCuisine and menu.
Hair salon, barberHairSalonUnder HealthAndBeautyBusiness.
SolicitorLegalServiceSchema.org also has Attorney, which is US-flavoured; LegalService is the neutral choice.
AccountantAccountingServiceUnder FinancialService.
Independent shopStore or a subtype such as BookStore, HardwareStoreMany subtypes exist; check the Store page on schema.org.
Consultancy, agencyProfessionalServiceA catch-all for offices that clients visit.

When two types are true

You can give an array: "@type": ["Restaurant", "BarOrPub"]. Only do this when both describe the whole business. A pub that serves food qualifies; a hairdresser that sells a few bottles of shampoo does not become a Store.

When LocalBusiness is the wrong type

If customers never meet you at a place, for example an online-only shop or a software company, Organization is the honest choice. A home-based trade that travels to customers can still use a LocalBusiness subtype, but how to handle the address and the areas covered is a website design question covered in the service-area coverage guide.

A complete block for a single location

This is a full block for a fictional practice. Every value here should be copied from your canonical business details, the same ones shown on the page. The phone number uses an Ofcom drama number range, so it is safe as an example.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Dentist",
  "@id": "https://example.co.uk/#practice",
  "name": "Millbank Lane Dental",
  "url": "https://example.co.uk/",
  "telephone": "+44 114 496 0321",
  "email": "hello@example.co.uk",
  "image": "https://example.co.uk/images/practice-front.jpg",
  "logo": "https://example.co.uk/images/logo.png",
  "priceRange": "ยฃยฃ",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "14 Millbank Lane",
    "addressLocality": "Sheffield",
    "addressRegion": "South Yorkshire",
    "postalCode": "S10 2AB",
    "addressCountry": "GB"
  },
  "geo": {
    "@type": "GeoCoordinates",
    "latitude": 53.38115,
    "longitude": -1.49872
  },
  "hasMap": "https://www.google.com/maps?cid=0000000000000000000",
  "openingHoursSpecification": [
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday"],
      "opens": "08:30",
      "closes": "17:30"
    },
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": "Friday",
      "opens": "08:30",
      "closes": "16:00"
    },
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": "Saturday",
      "opens": "09:00",
      "closes": "12:30"
    }
  ],
  "sameAs": [
    "https://www.facebook.com/example-dental",
    "https://www.instagram.com/example_dental"
  ]
}
</script>

A few details in that block are easy to get wrong:

Opening hours that parse, including the awkward ones

Hours are where most blocks fail quietly. The old openingHours text property, such as "Mo-Fr 09:00-17:00", is valid schema.org, but it is easy to mistype and cannot express exceptions. Use openingHoursSpecification with 24-hour times and full English day names.

SituationHow to write it
Closed for lunchTwo specifications for the same day: one closing at 12:30, one opening at 13:30.
Open past midnightOne specification, e.g. "dayOfWeek": "Saturday", "opens": "18:00", "closes": "02:00". The closing time is read as the following morning.
Open 24 hours"opens": "00:00", "closes": "23:59" for each day that applies.
Closed all day on a dateA dated specification with "opens": "00:00", "closes": "00:00".
Bank holiday or seasonal hoursA specification with validFrom and validThrough set to the dates, alongside the normal weekly ones.

A Christmas closure, for example, looks like this inside the array:

{
  "@type": "OpeningHoursSpecification",
  "opens": "00:00",
  "closes": "00:00",
  "validFrom": "2026-12-25",
  "validThrough": "2026-12-26"
}
โš ๏ธ Special hours in the markup do not update your Business Profile, and the profile does not update the markup. Change both, and change the hours printed on the page, on the same day. A block that still promises Saturday opening after you stopped opening Saturdays is worse than no hours at all.

Connecting the block to everything else: @id, url and sameAs

A LocalBusiness block that stands alone describes a business. One that carries a stable identifier and points to your other profiles describes your business, and lets other blocks on your site refer back to it.

@id

Give the business a permanent identifier: your homepage address followed by a fragment, such as https://example.co.uk/#practice. It is not a page a visitor opens; it is a name. Use exactly the same string everywhere the business is mentioned in markup, for example as the provider of a Service block or the publisher of an article. Change it once and every reference breaks.

url

The page that best represents this location. For a single-location business that is usually the homepage. For a branch it is the branch page, not the homepage.

sameAs

A list of profile addresses that are definitely this business: Facebook, Instagram, LinkedIn, a trade body membership page, a Companies House entry if you want to point at it. Keep the list short and accurate. A directory listing that shows an old address should be corrected before it goes into sameAs, not after. Checking what those listings say is the job of the NAP consistency guide, and this guide assumes that work is done.

geo

Take the coordinates from your pin in Google Maps: right-click the entrance and the first item in the menu is the latitude and longitude, which copies when clicked. Google recommends at least five decimal places. Put the point on the customer entrance, not the middle of the building or the car park behind it.

๐Ÿ’ก If the same business appears in markup from both your theme and an SEO plugin, give them the same @id. Parsers treat nodes with the same identifier as one entity, which is often the quickest way to stop two half-complete blocks competing.

Where the markup comes from on common platforms

Before you add anything, find out what already writes structured data on your site. Duplicated or conflicting LocalBusiness blocks are a common outcome of adding a plugin on top of a theme that already had one.

WordPress

Yoast SEO outputs Organization or Person in its schema graph; LocalBusiness comes from its paid Local SEO add-on. Rank Math has a Local SEO setting that switches the site entity to a LocalBusiness type with address and hours, with multi-location support in its paid tier. Some themes and page builders add their own block too. Pick one source, fill it in completely and switch off the others. If you hand-code instead, add the JSON-LD through a small site-specific plugin or the theme's header hook, not by pasting into a post.

Shopify

Most themes output Organization and WebSite on the homepage and Product on product pages, but not LocalBusiness. A shop with a physical counter can add a snippet to theme.liquid, guarded so it only renders on the homepage or a store page, or use a schema app. Check the rendered source afterwards; some apps inject a second Organization.

Wix and Squarespace

Both builders fill in some business information automatically. Wix lets you add custom structured data to a page in its SEO settings. Squarespace supports code injection on plans that include it. In both cases, view the published page source first so you do not end up with a second, contradictory block.

Custom sites and frameworks

Generate the block from the same data that fills the visible contact details, and output it with a JSON encoder: json_encode() in PHP, JSON.stringify() in JavaScript, json.dumps() in Python. In Next.js or Nuxt, render it on the server so it is present in the initial HTML rather than added after hydration.

Validator messages and what they usually mean

Message or symptomLikely causeFix
Missing field "address"The address is plain text in address, or absent.Use a PostalAddress object with the separate parts.
Invalid value in "opens" or "closes"12-hour times, "9am", or times with seconds in an odd format.Use HH:MM in 24-hour form, such as 17:30.
"dayOfWeek" not recognisedAbbreviations such as "Mon" or lowercase names in the specification.Full names like Monday, or the full URL form https://schema.org/Monday.
Two LocalBusiness items detectedTheme plus plugin, or plugin plus hand-coded block.Keep one; or give both the same @id and remove conflicting values.
Parsing error, whole block ignoredA trailing comma, a curly quote, or an apostrophe in the business name breaking a hand-built string.Output through a JSON encoder; test with the Schema Markup Validator.
Stars do not appear for your businessaggregateRating about your own business on your own site.Expected. Google does not show review stars for self-serving LocalBusiness or Organization reviews. See below.

About ratings in LocalBusiness markup

Since 2019 Google has not shown review rich results for reviews a business publishes about itself on its own site when the item is a LocalBusiness or Organization. You can still include aggregateRating if the page genuinely shows those reviews, but do not expect stars from it, and never mark up ratings copied from Google, Trustpilot or another platform. The rules for review markup in general are covered by the review schema guide.

The fix, step by step

Step 1

Find the markup you already have

Open your homepage and contact page, view the source and search for application/ld+json, then also search for itemtype= in case an older theme uses microdata. Paste the URL into the Schema Markup Validator to list every item it detects. Write down which blocks exist, which tool or template produces each one, and every value they state for name, address, phone and hours. You are looking for duplicates and for values that differ from your real details.

Step 2

Choose the most specific true type

Look up your trade in the schema.org type tree and pick the deepest type that honestly describes the whole business, such as Dentist, Plumber or AutoRepair. Use an array only when two types are both fully true. If nothing fits, step up one level, to ProfessionalService or Store for example, rather than choosing a near miss. Replace the generic LocalBusiness value in whichever single source you decided to keep.

Step 3

Complete the address and contact fields

Split the address into a PostalAddress with streetAddress, addressLocality, postalCode and addressCountry set to GB, written exactly as your canonical address. Add telephone in +44 format, url pointing to the page for this location, and an image of the premises or team. Leave out any field you would have to guess, since a missing value does less harm than a wrong one.

Step 4

Write opening hours in a form that parses

Replace free-text hours with an openingHoursSpecification array. Group days that share the same times, use full day names and 24-hour HH:MM times, and add a second entry for any day with a lunch break. For late closing, put the after-midnight time in closes on the same entry. Add dated entries with validFrom and validThrough for bank holidays and seasonal changes, and remove them once the dates pass.

Step 5

Add coordinates, @id and sameAs

Right-click your entrance in Google Maps, copy the coordinates and add them as a GeoCoordinates object with at least five decimal places. Give the business a permanent @id such as your homepage address followed by #business, and reuse that exact string anywhere else your markup refers to the business. Add a short sameAs list of profiles you control and have already checked for correct details, leaving out any listing that still shows old information.

Step 6

Make the markup match the visible page

Read the page as a visitor would and compare it field by field with the block. The phone number, address, hours and business name in the markup must all appear on the page in the same form, allowing only for the +44 formatting of the number. If the page does not show hours, add them to the page rather than keeping hours that live only in code. Remove any markup value that a visitor cannot see or confirm.

Step 7

Validate, publish and re-check

Test the live URL in the Schema Markup Validator for full schema.org correctness and in Google's Rich Results Test to confirm Google can read it, fixing any parsing error before anything else. After publishing, use URL Inspection in Search Console to request indexing of the page. Run the Local SEO Checker again to confirm the completeness finding has cleared, and put a reminder in your calendar to review hours before each bank holiday.

Keeping it right after today

Questions and answers

1. Does LocalBusiness schema improve my local rankings?

Google has not said that LocalBusiness markup is a ranking factor, and adding it will not lift a weak site on its own. What it does is state your type, address, hours and coordinates in an unambiguous form, which helps search engines connect your website to the right place and the right Business Profile. Think of it as removing a source of doubt rather than adding a boost. The businesses that benefit most are those whose details were previously unclear or inconsistent.

2. Which page should the LocalBusiness markup go on?

For a single-location business, put it on the homepage, and optionally on the contact page as well, using the same @id so both describe one entity. Do not add it to every page through a site-wide template unless your platform does so with identical values, because blog posts and product pages are not about the business location. For several branches, each branch page carries its own block for that branch only, rather than a list of every branch on the homepage.

3. Should I use JSON-LD or microdata?

Use JSON-LD. Google supports JSON-LD, microdata and RDFa, but recommends JSON-LD because it sits in one block that is easy to read, test and maintain without touching the visible HTML. Microdata spreads attributes through the page markup, so a template change can break it without anyone noticing. If an old theme outputs microdata and you add JSON-LD, remove the microdata version so you do not end up with two descriptions that slowly drift apart.

4. What schema type should I use if my trade is not listed?

Choose the nearest parent type that is still true rather than a specific type that is wrong. A dog groomer has no dedicated schema.org type, so LocalBusiness or ProfessionalService is more honest than PetStore unless you actually sell pet supplies. You can describe what you do in the description field and through Service blocks for each service. Check the schema.org type list occasionally, because new types are added from time to time.

5. How do I mark up bank holiday or Christmas opening hours?

Add extra OpeningHoursSpecification entries alongside your normal weekly ones, each with validFrom and validThrough set to the dates in question. For a day you are closed, set opens and closes both to 00:00. For shorter hours, give the actual times. Remove the dated entries after the period ends so the block stays tidy, and change the hours shown on the page and on your Business Profile at the same time, because each one is updated separately.

6. Can I include my Google reviews in aggregateRating?

No. Review markup should describe reviews that are collected and shown on your own site, not ratings copied from Google, Trustpilot or another platform. In addition, Google does not show review stars for reviews a local business publishes about itself on its own site, so even genuine first-party ratings will not produce stars for a LocalBusiness item. If you want to display third-party reviews, embed or link to them as visible content and leave them out of the markup.

7. Do I need both an Organization block and a LocalBusiness block?

Usually not for a single-location business, because LocalBusiness is itself a kind of Organization and can carry the logo, sameAs links and contact details. Multi-branch businesses often use one Organization for the brand and a LocalBusiness per branch, linked with parentOrganization. If a plugin already outputs an Organization and you add a LocalBusiness, give them the same @id or merge them, so search engines see one business rather than two similar ones.

Check your LocalBusiness markup

The Local SEO Checker looks at LocalBusiness schema completeness alongside NAP consistency across major citation sources, Business Profile signals, review velocity, geo-content coverage and your position in the map pack.

Open Local SEO Fixes โ†’
๐Ÿ’ฌ Got a problem?
Related Guides: All Local SEO Fixes  ·  NAP Inconsistency  ·  Multi-Location SEO  ·  Local SEO Guide  ·  Learning Hub

About aiwebpageseo

aiwebpageseo.com is a data-driven SEO and AEO (Answer Engine Optimisation) platform providing a free suite of technical SEO tools. Rather than relying on AI-theorised assumptions, the platform analyses live URL performance, delivering objective diagnostics, page speed metrics, CLS debugging, and site crawl data alongside actionable technical tutorials.