Website & schema markup · Beginner
How to Add Schema Markup to Your Website (WordPress, Wix, Squarespace, Shopify, Webflow, HTML)
Menu paths for adding LocalBusiness JSON-LD on WordPress, Wix, Squarespace, Shopify, Webflow and HTML sites, how to avoid duplicate schema from themes and plugins, and how to test it for local SEO.
Free tool for this guide
LocalBusiness Schema Markup Generator
Generate valid LocalBusiness JSON-LD — prefilled from your Google profile.
You have a block of LocalBusiness JSON-LD, or are about to generate one, and need to know what to do with it. This is the installation manual: where the block belongs, the menu path on each major platform, how to find schema your theme or plugin already added, how to test the live page, and the routine that keeps it truthful when hours change. Our free LocalBusiness Schema Markup Generator produces the code; the companion LocalBusiness schema markup guide covers type, properties and edge cases, so read it first if you have not chosen a type.
Before you paste anything
Three checks save an afternoon of debugging.
The facts. The block must say exactly what your Google Business Profile says: same name, same phone with country code, same address, same hours. If the profile is wrong, fix it first; the markup is a copy, not the source. Our NAP consistency guide covers what “the same” means.
The page. Google’s structured data guidelines say markup belongs on the page it describes and must not describe content the visitor cannot see, so that page must show the address, phone and hours in its HTML. For one location, the homepage or contact page; for several, each location’s own page.
The format. Code fields (Squarespace, Webflow, Shopify, a WordPress HTML block) want the full script tag, which the generator’s Copy JSON-LD button gives you. Structured data fields (Wix, SEO plugins’ schema tabs) want the JSON alone, which its Download button saves. Never paste via Word or Google Docs; curly quotes break JSON.
Where the block belongs on a page
Google accepts JSON-LD in the <head> or the <body>; both are read. The head is the convention, and we prefer it where the platform offers a field, because page builders rarely touch head code once saved. The body is what a WordPress Custom HTML block or a Shopify Custom Liquid section gives you; that is fine. Google’s LocalBusiness documentation shows the block in the head as an example, not a requirement.
Two placements fail. A block inside an iframe (most embed widgets) belongs to the iframe’s document, not your page. A block injected by a tag manager is read once Google renders JavaScript, but it arrives late and vanishes when someone pauses the tag; last resort only.
One business node per page. Other block types (WebSite, BreadcrumbList, Article, Product) can sit alongside it; two blocks both claiming to be the business cannot, and a site-wide business block does nothing on a blog post while blocking the one-node-per-location pattern you will want with a second site.
Platform-by-platform instructions
Menu labels move. These paths are correct as far as we know at the time of writing, but platforms reshuffle settings often; if a label is missing, search the help center for “custom code” or “structured data” before assuming the feature is gone.
WordPress
Three routes, in order of simplicity.
A Custom HTML block. Edit the homepage or contact page, add a Custom HTML block, paste the full script tag, update. It renders nothing visible and Google reads it from the body. The catch: WordPress strips <script> tags for users without the unfiltered_html capability, which includes WordPress.com plans below Business and most multisite editors, so check the live source afterwards.
A code snippets plugin. WPCode (formerly Insert Headers and Footers), Code Snippets and similar plugins add code to the head. In WPCode: Code Snippets → Add Snippet → Add Your Custom Code, type HTML Snippet, paste, Auto Insert into the Site Wide Header, then use conditional logic to limit it to one page; otherwise it lands on every page.
The SEO plugin. Rank Math, All in One SEO, SEOPress and Yoast (via its Local SEO add-on) can build a LocalBusiness block from a form, some only in a paid tier. Then the plugin is the single source; do not paste a second block. Whatever you choose, never edit the parent theme’s header.php; the next update deletes it.
Wix
Wix has a dedicated field and expects the JSON without script tags. In the Editor open Pages & Menu, hover the page, click the three dots, choose SEO basics, open the Advanced SEO tab, expand Structured Data Markup, click Add New Markup, paste, name it and apply. Publish; the preview does not carry the markup.
Wix can also generate a LocalBusiness preset for the homepage from Settings → Business Info. Check the live homepage’s source first; if a block is already there, edit or switch off the preset in the dashboard’s SEO Settings rather than run two. Settings → Custom Code also accepts head code on paid plans; for structured data, use the per-page panel.
Squarespace
In the Pages panel, hover the page, click the gear icon, open the Advanced tab and paste the full script tag into Page Header Code Injection. Code injection is a paid-tier feature; on the entry plan the field is absent. Settings → Advanced → Code Injection → Header applies to every page; avoid it.
Squarespace adds its own LocalBusiness block to the homepage once Business Information (address, hours) is filled in. Check view-source first: if that block is present and correct, keep it and add nothing else; otherwise clear the Business Information fields and manage the block yourself. Never run both.
Shopify
Two routes. The theme file: Online Store → Themes → the three dots next to your live theme → Edit code → Layout → theme.liquid, paste before the closing head tag, wrapped in a Liquid condition so it appears on one page only:
{%- if request.page_type == 'index' -%}
<script type="application/ld+json">
...your JSON-LD here...
</script>
{%- endif -%}
For a contact page the condition becomes request.page_type == 'page' and page.handle == 'contact'. The second route avoids theme files: in Customize, open the homepage or page template, Add section → Custom Liquid, paste the full script tag, save. It sits in the body, which is fine.
Before either, view the source of your live homepage. Most themes emit an Organization block with store name, logo and social links, plus a WebSite block; in Dawn they come from the header section. They are not duplicates of a Bakery or HairSalon node: leave them if the name and URL match yours, edit them if they carry a wrong phone or a rating.
Webflow
In the Designer’s Pages panel, hover the page, click the gear to open Page settings, scroll to Custom code and paste the full script tag into the Inside <head> tag field. Save and publish. Custom code needs a paid site plan, and the per-page field has a character limit; trim whitespace if a long block is refused. Site settings → Custom code → Head code is site-wide; avoid it. On a Collection page template the same field accepts CMS fields via Add Field.
Google Sites, Carrd and static HTML
New Google Sites has no head access and its Embed code block renders in an iframe, so the JSON-LD never becomes part of your page. Honest advice: you cannot reliably add LocalBusiness markup to a Google Site; make the visible name, address and phone perfect and let the profile do the work, or move platform.
Carrd allows it on Pro plans: add an Embed element, set Type to Code, Style to Hidden, placement to Head, paste the full script tag and publish.
On a hand-coded site, paste the script tag before </head>. With a static site generator (Astro, Hugo, Jekyll, Eleventy), put it in the layout and pull the values from front matter so a phone change is one edit. Check the deployed page’s source, not the local file.
Find and remove duplicate or conflicting schema
Before your block goes live, find out what is already there. Open the live page, view the source (view-source: in front of the URL in Chrome), search for application/ld+json and read each match. Then run the URL through the Rich Results Test, which also catches blocks injected by JavaScript.
Look for three things: a second LocalBusiness block (or subtype) from a theme, plugin or platform feature; an Organization block whose name, phone or URL disagrees with yours; and any aggregateRating or review node copying your Google rating, which breaks Google’s review guidelines and must go.
One source of truth per fact. If a plugin already produces a correct LocalBusiness block, use it; do not paste another. If the theme’s block is wrong, edit or disable it; two blocks disagreeing on the phone are worse than none. A correct Organization node and your LocalBusiness subtype can coexist, brand and place; where possible give the Organization node an @id and reference it with parentOrganization, as the pillar guide shows.
Multi-location sites
Every location gets its own page, and every page gets exactly one LocalBusiness node for that location: its own address, phone, hours, map link and url, plus parentOrganization pointing at a brand Organization node on the homepage. Three addresses in one block on a shared contact page describe none of them. Give each node a stable, URL-shaped @id, the page URL plus a fragment such as #location or #localbusiness (the generator emits the latter); the fragment does not matter, but changing it later does, and an @id built from a post ID or build hash makes Google see a new entity every deploy. Webflow Collection templates and Shopify page.handle conditions give one block per location page from one template; elsewhere, paste per page. The matching profile structure is in our multi-location Google Business Profile guide.
Test after deploy
Test the live URL, never the editor preview. Wix, Webflow and Squarespace only carry the code after publishing, and a caching plugin or CDN can serve the old page for an hour; purge it if the block does not show.
Run the page through the Rich Results Test in URL mode: you want “Local business” detected with no errors; warnings are recommended properties you chose to skip. Then the schema.org validator, which checks the vocabulary rather than Google’s rules and catches a misspelled property such as telephon. In Search Console, URL Inspection with Test Live URL confirms Google renders the block; request indexing, and watch the Unparsable structured data report for broken JSON. There is no Local Business report; its absence means nothing.
Keep it in sync when hours or phone change
The block is one more copy of your name, address, phone and hours, and it drifts like every other copy unless someone owns it. Our owner routine:
- Write down where the block lives (page, plugin or section, field) next to your Google Business Profile login; redesigns lose head code first, and nobody remembers where it was.
- When hours, phone or address change on the profile, change the block the same day; regenerate it or edit the JSON. Hours drift most; the wider profile routine is in our guide to optimizing your Google Business Profile.
- Do not encode every holiday; use special hours on the profile instead.
- Re-test the live URL quarterly, and the same day after any theme switch or redesign.
Worked example: a Shopify bakery
Crumb & Co. is an Asheville, North Carolina bakery selling cakes online through a Shopify store on the Dawn theme. The footer shows address, phone and hours, the Google Business Profile links to the homepage, and the owner has been told the site “has no schema”.
Step one is looking. View-source on the live homepage shows two application/ld+json blocks: the theme’s Organization block with store name, logo, URL and Instagram link, and a WebSite block. No LocalBusiness, no rating, nothing wrong. Both stay.
Step two is the LocalBusiness Schema Markup Generator: search “Crumb & Co Asheville”, prefill from the profile, confirm the type is Bakery, compare hours with the door (the profile said Saturday closes at 15:00, the door says 16:00; the profile is fixed first), add the Instagram URL to sameAs, leave the rating fields empty, copy.
Step three is placing it without touching theme.liquid: in Customize, on the homepage, Add section → Custom Liquid, paste, save. The theme’s Organization block is untouched; it has no @id to reference, so parentOrganization is left out. Name and URL match, which is what matters.
{
"@context": "https://schema.org",
"@type": "Bakery",
"@id": "https://crumbandco.example/#localbusiness",
"name": "Crumb & Co.",
"url": "https://crumbandco.example/",
"image": "https://crumbandco.example/cdn/shop/files/storefront.jpg",
"telephone": "+18285550142",
"address": {
"@type": "PostalAddress",
"streetAddress": "48 Haywood Street",
"addressLocality": "Asheville",
"addressRegion": "NC",
"postalCode": "28801",
"addressCountry": "US"
},
"openingHoursSpecification": [
{ "@type": "OpeningHoursSpecification", "dayOfWeek": ["Tuesday", "Wednesday", "Thursday", "Friday"], "opens": "07:00", "closes": "15:00" },
{ "@type": "OpeningHoursSpecification", "dayOfWeek": "Saturday", "opens": "07:00", "closes": "16:00" }
],
"sameAs": ["https://www.instagram.com/crumbandco.example"]
}
Step four is checking: the Rich Results Test in URL mode shows Local business with no errors, the schema.org validator lists three nodes (Organization, WebSite, Bakery), and Search Console gets a request to index. Then the Google Business Profile Optimizer is run on the profile, because the exercise exposed an hours error and a thin photo set, which matter more for the local pack than any markup. Honest expectation for the schema: no ranking change, one less thing for Google to guess.
Common mistakes
- The wrong wrapper. Script tags in Wix’s structured data field, or bare JSON in a code field; the block is ignored or printed as text.
- Site-wide injection. The business block in a global header, so every product and blog post claims to be the business.
- Curly quotes. JSON pasted through Word, Google Docs or a chat app fails to parse.
- Two sources of truth. A built-in block, a plugin’s block and a pasted one, each with a different phone. Pick one.
- Testing the preview. The preview often lacks the code and the live page may be cached; test the published URL after a purge.
- Forgetting it exists. Hours change on the profile and not in the block, or a redesign drops it. Write down where it lives; check quarterly.
Do this now
- View the source of the live page that shows your address and hours and read every
application/ld+jsonblock. - Fix anything wrong on the Google Business Profile, then generate the block with the LocalBusiness Schema Markup Generator, prefilled from the profile.
- Follow your platform’s path above: one block, on the one page it describes, one per location page if you have several.
- If the theme or platform already emits a business block, pick one source and remove or edit the other.
- Publish, purge caches, run the live URL through the Rich Results Test and the schema.org validator, then request indexing in Search Console.
- Write down where the block lives and add a quarterly reminder next to your profile’s special hours check.
- Continue with the website items in our local SEO checklist and the site-side advice in Google Business Profile SEO; both move rankings more than markup.
Put this into practice
Run the free Schema Generator now
Fill the form or prefill it from your Google Business Profile and get valid JSON-LD for the right schema.org type — address, geo, opening hours, sameAs and more — ready to paste into your site.
Frequently asked questions
Does schema markup go in the head or the body of the page? +
Either. Google reads a JSON-LD script block anywhere in the HTML, so the head, a Custom HTML block in the page body or a Shopify Custom Liquid section all work. The head is the convention because page builders are less likely to strip or reformat code there. What does not work is a block inside an iframe embed, or one that only appears after a slow script runs.
Do I need a plugin to add schema markup to WordPress? +
No. A Custom HTML block on the page that describes your business works on any self-hosted WordPress site where your user is allowed to save script tags. A code snippets plugin is the tidier route when you want the block in the head, and most SEO plugins can generate a LocalBusiness block from a form. Avoid editing a parent theme's header file, because the next update deletes your change.
Should I add LocalBusiness schema to every page of my site? +
No. Put it on the page that represents the business: the homepage or contact page for one location, and each location's own page if you have several. Google's guidelines say structured data should sit on the page it describes, and a business block on every blog post and product page adds nothing while making a multi-location setup harder later. Other block types such as Product or Article belong on their own pages.
How do I know if my website already has schema markup? +
Open the live page, view the source and search for application/ld+json; every match is one block, and you can read what each one claims. Then run the same URL through Google's Rich Results Test, which lists every detected item and its errors, including blocks injected by JavaScript. Themes, SEO plugins and platforms such as Wix and Squarespace often add an Organization or LocalBusiness block you did not write.
Can I add schema markup with Google Tag Manager? +
You can, and Google says it processes structured data injected by JavaScript once the page is rendered. In our experience it works but is fragile: the tag fires late, a consent banner blocks it, or someone pauses the container and the markup vanishes without anyone noticing. Treat it as a last resort when you have no access to the page code, and test the live URL in the Rich Results Test rather than the container preview.
How long does it take Google to pick up new schema markup? +
Google reads it the next time it crawls the page, which can be hours for a busy site or weeks for a quiet one. Requesting indexing in Search Console's URL Inspection tool usually shortens that to a few days. Whether anything visibly changes in search is a separate question: valid markup makes a page eligible for a rich result but does not guarantee one, and for a business marking up its own site the visible change is usually small.
About the author. Locan Team — local SEO specialists who have spent years optimising Google Business Profiles and local rankings for real businesses, and who now publish free tools and guides on Locan. Why everything here is free →
Related guides
Keep going
LocalBusiness Schema Markup: The Complete Guide With JSON-LD Examples
What LocalBusiness schema markup does for local SEO (and what it does not), choosing the type and properties, hours and review rules, single and multi-location JSON-LD examples, and validation.
Read the guide →NAP Consistency in Local SEO: How to Find and Fix Name, Address, and Phone Mismatches
What NAP consistency does for local SEO today, which variations Google forgives, a free audit with search operators, a fix order from Google Business Profile to aggregators, and a moves checklist.
Read the guide →The Local SEO Checklist: 60 Steps From Setup to Ranking (Free)
A free local SEO checklist: 60 tasks in seven phases, from Google Business Profile setup to reviews, citations, schema and AI visibility, with a 30/60/90-day order and the free tool for each step.
Read the guide →How to Optimize Your Google Business Profile: The Complete Step-by-Step Guide
Every Google Business Profile field explained in the order we complete them for clients, from verification and categories to photos, posts and reviews, with a 30-minute checklist.
Read the guide →Google My Business SEO: The Complete Guide to Ranking Your Business Profile
Google My Business SEO explained: how Google ranks a Google Business Profile, the on-profile playbook in priority order, reviews, website, citations, tracking and a monthly local SEO routine.
Read the guide →Managing Multi-Location Google Business Profiles: A Practical System
A working system for multi-location Google Business Profiles: who gets a profile, ownership and roles, bulk verification, a template plus local layer, reviews per location and a monthly scorecard.
Read the guide →Stay in the loop
New guides and tools, straight to your inbox
One short email when a new tool ships or a guide gets a major update. No drip campaigns, nothing to buy — unsubscribe any time with one click.