What is JSON-LD? Format, examples and where to put it
Kane Vu
Short answer
JSON-LD is a format for writing facts about a page as labeled data inside a script tag: what the business is called, where it is, what a product costs. Visitors never see it, it can sit in the head or the body of a page, and Google recommends it as the easiest of the three structured data formats to maintain. One stray comma or curly quote can stop a machine from reading the whole block, so it pays to be able to read one yourself.
What is JSON-LD, in plain words?
JSON-LD is a small block of labeled facts in a page’s code. A visitor sees a shop name and a phone number on the page. A machine reading the block is told which is which: this is a bike store, this is its name, this is its number. For being named by AI, that is the modest point of it: your identity is stated where a machine does not have to guess it.
The name is short for JSON for Linked Data, as json-ld.org’s page title has it. JSON is a plain text data format (RFC 8259, December 2017), and the W3C’s JSON-LD 1.1 Recommendation of July 16, 2020 builds on it, defining “a JSON-based format to serialize Linked Data”.
JSON-LD is only the container. The words inside usually come from schema.org, a shared vocabulary, and that pairing is what people mean by a JSON-LD schema. Our guide to schema markup covers what markup is for and which types a business should add. This page covers the syntax, so you can open your own site and tell a developer what is wrong.
How do you read a JSON-LD block, line by line?
Here is a complete block for an invented shop. Every name, number and address in this guide is made up.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BikeStore",
"name": "Quillfern Bike Works",
"url": "https://www.example.com",
"telephone": "+1-503-555-0142"
}
</script>| What you see | What it says | What to check |
|---|---|---|
| The script tag | This is data, not a program. The HTML standard calls it a data block, “not processed by the user agent”, so a browser neither runs it nor shows it | The type reads exactly application/ld+json |
| Curly braces | The start and end of one thing being described | Every opening brace has a closing one |
| @context | Which dictionary the words come from: here, schema.org | It appears once in the block, not twice |
| @type | What kind of thing this is | The exact name from schema.org, capitals included |
| name, url, telephone | The properties: one fact each | Each value matches what the page shows |
Three bits of punctuation do most of the work.
- Double quotes wrap every label and every text value. RFC 8259 says “A string begins and ends with quotation marks”, and it means the straight kind a code editor types.
- A colon joins a label to its value.
- A comma separates one label and value from the next. The last pair has none, because in the JSON grammar a comma must be followed by another item.
Capitals count too. The W3C specification says “All keys, keywords, and values in JSON-LD are case-sensitive.” To check a type name, add it to the end of schema.org’s address. On November 4, 2026, schema.org/BikeStore opened, while schema.org/bikestore and schema.org/BicycleStore both returned a not-found page.
What do nesting, @id and @graph add?
Three more pieces of syntax turn up on real sites, each for one plain reason.
Nesting, when one thing belongs to another. An address is not a fact about the page: it belongs to the store. So it goes inside the store, with its own @type.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BikeStore",
"name": "Quillfern Bike Works",
"url": "https://www.example.com",
"address": {
"@type": "PostalAddress",
"streetAddress": "410 Example Street",
"addressLocality": "Portland",
"addressRegion": "OR",
"postalCode": "97201",
"addressCountry": "US"
},
"sameAs": [
"https://social.example.com/quillfern",
"https://directory.example.com/quillfern"
]
}
</script>The value of address is a second set of curly braces, and the comma after its closing brace is there because the store has another property still to come. Square brackets hold a list, here the store’s profiles on other sites. Which details a block about your business should hold is the subject of our guide to Organization schema.
@graph, when a page holds several separate things. One block gets one @context, with a list of things under it. The W3C specification says a top-level @graph “can be useful for saving the repetition of @context”.
@id, when one thing needs to point at another. Here the store gets a unique label, and the article names its publisher by pointing at that label, without repeating the store’s details.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "BikeStore",
"@id": "https://www.example.com/#store",
"name": "Quillfern Bike Works",
"url": "https://www.example.com"
},
{
"@type": "Article",
"headline": "How often to replace a bike chain",
"datePublished": "2026-10-05",
"publisher": {"@id": "https://www.example.com/#store"}
}
]
}
</script>The value of @id is written like a web address, but here it works as a label: the W3C specification says @id is “used to uniquely identify node objects”, and the #store ending is simply our choice. Google’s general structured data guidelines (updated July 10, 2026) recommend @id for items that are more helpful linked together. If you see @id on your own site, check one thing: the label is spelled identically everywhere it appears.
JSON-LD vs Microdata vs RDFa: what changes in daily work?
JSON-LD is one of three formats Google accepts. In its introduction to structured data (updated December 10, 2025), Google says “all 3 formats are equally fine for Google, as long as the markup is valid and properly implemented”. It recommends JSON-LD “if your site’s setup allows it”, calling it “the easiest solution for website owners to implement and maintain at scale”.
| JSON-LD | Microdata | RDFa | |
|---|---|---|---|
| How it is written | One block of labeled data in a script tag, apart from the visible text | Attributes on the HTML tags around the visible text: itemscope, itemtype, itemprop | Attributes on the HTML tags around the visible text: vocab, typeof, property |
| Who can change it | Anyone who can paste code into one field or template | Whoever edits the page’s HTML | Whoever edits the page’s HTML |
| After a redesign | The block survives if the new template keeps it | New HTML can drop the attributes without anyone noticing | Same as Microdata |
| How to spot it in page source | Search for application/ld+json | Search for itemprop | Search for typeof |
JSON-LD is easy to change because it is separate from the text, and that same separation means nothing keeps the two in step. If your site already has valid Microdata, Google’s wording gives you no reason to rewrite it for Google’s sake. Some platforms decide for you: Wix “only accepts structured data using JSON-LD markups”.

Where do you put JSON-LD: head or body?
Head or body: both work. Google describes JSON-LD as “embedded in a <script> tag in the <head> and <body> elements of an HTML page”. Our suggestion is the head, because it keeps the code clear of whatever edits the page content. That is a convenience, not a rule.
On which page. “Put the structured data on the page that it describes, unless specified otherwise by the documentation,” say Google’s general guidelines. It must also match what is there: “Don’t mark up content that is not visible to readers of the page. For example, if the JSON-LD markup describes a performer, the HTML body must describe that same performer.” Since no visitor ever sees the block, this is the easiest rule to break by accident.
One block or several. Either. The same guidelines say “Google Search understands multiple items on a page, whether you nest the items or specify each item individually.” A theme writing one block and a plugin writing another is fine, provided they do not disagree.
Written by the server, or added by JavaScript?
A block can reach a page in two ways. The server can write it into the HTML it sends, or a script, a widget or a tag manager can add it after the page opens in a browser. Google accepts both: “Google can read JSON-LD data when it is dynamically injected into the page’s contents, such as by JavaScript code or embedded widgets in your content management system.” Its page on generating structured data with JavaScript (updated December 10, 2025) gives the steps for Google Tag Manager, and two warnings. Product markup added this way “can make Shopping crawls less frequent and less reliable”, which matters for prices and availability. Typing facts into the tag manager, instead of reading them from the page, “increases the risk of having a mismatch between page content and the structured data”.
Outside Google, less is known. The crawler pages of OpenAI, Anthropic and Perplexity that we read on November 4, 2026 do not say whether their bots run JavaScript. The nearest evidence is a study Vercel and MERJ published on December 17, 2024 from their own traffic data. It found that “none of the major AI crawlers currently render JavaScript”, naming the bots of OpenAI, Anthropic and Perplexity among them, while “Google’s Gemini leverages Googlebot’s infrastructure”. It is nearly two years old, and those bots may have changed.
| How the block arrives | In View page source? | A reader that runs no JavaScript | |
|---|---|---|---|
| Written by the server | Yes | Reads it | Gets it |
| Added by custom JavaScript or a widget | No | Reads it after rendering | Does not get it |
| Added by a tag manager | No | Reads it after rendering | Does not get it |
To test your own page, open it in a browser, choose View page source and search for application/ld+json. That is what a reader gets with no JavaScript. If nothing turns up, right-click the page, choose Inspect and search there: that is the page after scripts have run. A block found only in Inspect was added by JavaScript.
This is also why the MWY checker can disagree with Google. It reads “the HTML the server returns, without running JavaScript”, so a tag manager block counts as missing even though Google can read it. That does not mean Google missed it: the block reaches only readers that run scripts. Our suggestion is to keep the facts about who you are in the server’s HTML.
Which syntax mistakes break a JSON-LD block?
The W3C specification says “A JSON-LD document is always a valid JSON document”, so one JSON error spoils the whole block, not only its line. Google’s help page for the Unparsable structured data report in Search Console (read November 4, 2026) says the intended type of such a block could not even be determined.
We ran every sample below through JSON.parse, the strict parser built into Node.js 24, on November 4, 2026. The messages are its own; other tools word them differently.
A comma after the last item. It is easy to leave one behind when you delete a line.
{
"@context": "https://schema.org",
"@type": "BikeStore",
"name": "Quillfern Bike Works",
}The parser said: Expected double-quoted property name in JSON at position 96 (line 5 column 1). It reached the closing brace while still waiting for another label.
Curly quotes pasted from a document. Word processors turn straight quotes into curly ones. They look nearly the same to you, and they are not quotes at all to a parser.
{
"@context": "https://schema.org",
"@type": "BikeStore",
"name": “Quillfern Bike Works”
}The parser said: Unexpected token, pointing at the first curly quote, followed by “is not valid JSON”.
A missing quote. The text never closes, so the parser runs into the line break.
{
"@context": "https://schema.org",
"@type": "BikeStore",
"name": "Quillfern Bike Works,
"url": "https://www.example.com"
}The parser said: Bad control character in string literal in JSON at position 94 (line 4 column 33).
A missing bracket. Here the address never closes.
{
"@context": "https://schema.org",
"@type": "BikeStore",
"address": {
"@type": "PostalAddress",
"addressLocality": "Portland"
}The parser said: Expected ‘,’ or ‘}’ after property value in JSON at position 142 (line 7 column 2). Notice that it points at the end of the block, not at the spot where the brace is missing. When the fault is hard to find, Google’s advice is to “try starting from an empty object, then add back content from your broken code piece by piece until you find the error.”
Wrong capitals in @type. This one is a trap.
{
"@context": "https://schema.org",
"@type": "bikestore",
"name": "Quillfern Bike Works"
}The parser said nothing, because this is valid JSON. It is still the wrong word, by the case-sensitivity rule quoted earlier. Only a check against the vocabulary catches it.
HTML inside a value. The outcome depends on the HTML. Plain tags pass JSON.parse, and the value then simply holds the tags as text. A double quote inside the value does break the block.
{
"@context": "https://schema.org",
"@type": "BikeStore",
"description": "See our <a href="https://www.example.com/prices">prices</a>"
}The parser said: Expected ‘,’ or ‘}’ after property value in JSON at position 97 (line 4 column 36). The quote after href= ended the text early. A closing script tag inside a value is worse, since it can end the block itself, and the W3C tells authors to avoid such sequences. The safe habit is plain text in every value.
Testing a block that does parse is a separate step, covered in our guide to schema markup validation.

How do you add JSON-LD on WordPress, Shopify, Squarespace, Wix and Webflow?
Each line comes from the vendor’s own documentation, read on November 4, 2026. First search your page source for application/ld+json, because your platform may already write a block.
- WordPress. The wp_head hook, for a developer or a plugin, “Prints scripts or data in the head tag on the front end.” A Custom HTML block is the other route, but WordPress strips script tags from it when the person saving lacks the unfiltered_html capability, for example a Contributor.
- Shopify. The Liquid reference describes a structured_data filter that turns a product or article object into schema.org data, inside a script tag in your theme code. Duplicate the theme first, as the help center advises.
- Squarespace. It “automatically generates structured data” for blog posts, events, local businesses, organizations, products and websites, which you cannot edit or remove. To add your own, Code Injection (on Core, Plus, Advanced and some legacy plans) adds code to the head of every page, or of one page through its settings.
- Wix. In the editor, go to Pages & Menu, More Actions next to the page, SEO basics, the Advanced SEO tab, Structured Data Markup, then +Add New Markup. A page can hold up to five markups, each under 7,000 characters.
- Webflow. Webflow University says JSON-LD is added “as a script tag in the head of your page through Webflow’s custom code settings.”
Do AI assistants read JSON-LD?
Of the companies behind ChatGPT, Gemini, Claude and Perplexity, only Google has published a statement we could find. It sits in Google’s guide to generative AI features in Search, such as AI Overviews and AI Mode (updated July 10, 2026), under the heading “Overfocusing on structured data”:
Structured data isn’t required for generative AI search, and there’s no special schema.org markup you need to add. However, it’s a good idea to continue using it as part of your overall SEO strategy, as it helps with being eligible for rich results on Google Search.
That guide names neither JSON-LD nor the separate Gemini app. For the others, this is what we read on November 4, 2026.
- ChatGPT. OpenAI’s overview of its crawlers does not mention JSON-LD, schema or structured data.
- Claude. Anthropic’s help page on its crawlers does not mention them either.
- Perplexity. Perplexity’s crawler page does not mention them either.
We found no page from OpenAI, Anthropic or Perplexity that says whether their systems use JSON-LD. A bot that fetches your page receives a server-written block along with the rest of the HTML, but what it does with that block is not published. Silence is not proof either way. Two small outside tests point to little effect. In one page tested by searchVIU, a maker of SEO software, in October 2025, none of five AI systems used a price given only in JSON-LD. Ahrefs followed 1,885 pages that added schema and found “no major uplift” in citations after 30 days (May 2026). Those pages were already being cited, and searchVIU did not test training or indexing, so neither settles the question for a page AI does not yet cite.
So the documented reason to write JSON-LD is Google’s own: eligibility for rich results. Beyond that, it is a low-cost way to state facts plainly.
Where the figures come from
- searchVIU: “Schema Markup and AI in 2025”, tested October 30, 2025, on one page about a fictional product. searchVIU sells SEO software, and its post counts its own tests in more than one way.
- Ahrefs: a study published May 11, 2026 of 1,885 pages that added JSON-LD between August 2025 and March 2026, against 4,000 control pages, on citations in AI Overviews, AI Mode and ChatGPT over 30 days. Ahrefs sells SEO software too, and says the schema often came with other changes it could not separate.
Both are vendors’ own work, so read them as hints, not rules.
What the MWY checker does and does not do with JSON-LD
The free AI visibility checker reads the HTML the server returns from your home page and up to 7 inner pages, without running JavaScript. It finds JSON-LD in the head or the body, in separate blocks, nested or under @graph. One of its 24 items asks whether Organization or LocalBusiness markup exists, with a name, contact details and a logo.
Four things follow from how it reads.
- A block added by JavaScript or a tag manager counts as missing. Check View page source before you conclude a block is gone.
- A block that does not parse counts as missing. The checker does not point at the comma or the quote. Use the samples here to find it.
- A type with the wrong capitals is not recognized. It reads bikestore as a type it does not know.
- Microdata and RDFa do not count toward that item, even where Google accepts them.
Pro opens soon. Its fix for this item is a JSON-LD snippet filled in with what the checker found on your site, for you to check line by line.
The checker does not validate every type or property, and does not predict which rich results Google will show. It does not claim that a correct block will make an assistant name you: nobody outside the AI companies controls that. It tells you whether the HTML your server sends says who you are in a form a machine can read.
Questions people ask
Does JSON-LD go in the head or the body?
Either works. Google describes JSON-LD as embedded in a script tag in the head and body elements of an HTML page, and the W3C specification describes a script element with the type application/ld+json. Put it on the page it describes. We suggest the head, to keep it clear of page content edits, but that is a convenience, not a rule.
Is JSON-LD the same as schema markup?
No. JSON-LD is the format: the way the data is written. Schema.org is the vocabulary: the words used inside it, such as BikeStore or telephone. Schema markup usually means the two together, because Google recommends JSON-LD for structured data. The same schema.org words can also be written in Microdata or RDFa.
Can I add JSON-LD with Google Tag Manager?
Yes, and Google documents the steps: add a Custom HTML tag, paste the block and publish the container. Google can read it after rendering the page. A reader that runs no JavaScript will not get it, and Google warns that such markup can make Shopping crawls less reliable for fast-changing prices. For facts about who you are, the server HTML is the safer place.
Why does my JSON-LD show a parsing error?
A parsing error means the block is not valid JSON, so it cannot be read at all. Causes include a comma after the last item, curly quotes pasted from a document, and a missing quote or bracket. Google suggests starting from an empty object and adding content back piece by piece until the error returns, which shows you the line at fault.
How do I find the JSON-LD on my website?
Open the page in a browser, choose View page source and search for application/ld+json. Each match is one block, and what you see there is what a reader that runs no JavaScript receives. If the search finds nothing, try the Inspect panel of your browser: a block that appears only there was added by JavaScript after the page opened.
More guides
- Schema markup validation: which test to use and what the errors mean
Two tests, two different questions, and a list of what neither of them will ever catch for you.
- JavaScript SEO: what Google renders and AI crawlers may not
A page can look complete to a visitor and to Google and still be close to empty for an AI bot, and two minutes in a browser will tell you which.
- Open Graph tags: image size, the tags you need and how to test them
The image size each platform really publishes, a head block to copy, and what to do when a fixed tag keeps showing the old picture.
Is your website ready for AI assistants to name it?
Paste your website address and get your AI visibility score and the five things to fix first in a few seconds. Free, no sign-up.