JSON-LD Explained: Syntax, @id, @graph, Examples
JSON-LD (JavaScript Object Notation for Linked Data) is a way of writing structured data as JSON so that machines know exactly what each value means. On websites, it sits in a <script type="application/ld+json"> tag and describes the page’s content (an article, a product, a business, a person) using the schema.org vocabulary. It’s the format Google recommends for structured data, and four keywords (@context, @type, @id and @graph) do almost all the work.
This guide is for marketers and developers who can already copy a snippet but want to understand it well enough to write one, fix one, or connect several into a graph. It covers the syntax, the difference between nesting and referencing, where the script goes, and a complete example.
On this page
- What is JSON-LD used for?
- JSON vs JSON-LD: what’s the difference?
- The four keywords: @context, @type, @id and @graph
- Nesting vs referencing
- Where does JSON-LD go on a page?
- A complete example graph
- Why Google recommends JSON-LD over Microdata and RDFa
- Getting JSON-LD right across a site
What is JSON-LD used for?
It’s used to publish structured data: explicit statements about the things a page describes. The JSON-LD project site calls it “a lightweight Linked Data format” that is easy for humans to read and write, and the W3C published JSON-LD 1.1 as a Recommendation on July 16, 2020. Adoption is still climbing: the HTTP Archive’s 2024 Web Almanac found JSON-LD on 41% of pages, up from 34% in 2022, with WebSite the most common type (12.73% of mobile pages), followed by Organization (7.16%).
In SEO, it does three jobs:
- Tells search engines what the page is. Google’s introduction to structured data describes it as “a standardized format for providing information about a page and classifying the page content”.
- Makes pages eligible for rich results such as review stars, product prices, event listings and breadcrumbs. Google’s introduction cites publishers that measured the effect: Food Network converted 80% of its pages to enable search features and saw a 35% increase in visits, and Rakuten found users spent 1.5x more time on pages with structured data.
- Declares entity facts about your organization, people and services, which helps engines, including AI assistants, describe you correctly. Our guide to structured data for AI search covers which types matter for that.
It isn’t a ranking lever on its own. Google’s general structured data guidelines say a structured data manual action removes rich result eligibility but “doesn’t affect how the page ranks in Google web search”.
JSON vs JSON-LD: what’s the difference?
JSON is a data format; JSON-LD is JSON with agreed meaning. A plain JSON object with a key called name could mean anything. In JSON-LD, the @context maps name to a defined term in a vocabulary, so every consumer reads it the same way.
The practical differences:
- Every document is valid JSON. Any JSON parser can read it. Break the JSON (a trailing comma, a smart quote) and you break the linked data too.
- It adds keywords that start with
@. They’re reserved, and you can’t invent new ones. - It gives things identity. With
@id, two blocks on two different pages can talk about the same organization.
The diagram below labels each part of a small block.
Scroll the diagram sideways to see all of it.
The four keywords: @context, @type, @id and @graph
Four keywords cover nearly every SEO use of the format. The definitions below come from the JSON-LD 1.1 specification.
@contextis “used to define the short-hand names that are used throughout a JSON-LD document”. For SEO it’s almost always"https://schema.org", which is why"name"means schema.org’sname.@typeis “used to set the type of a node”. It’s the schema.org type:Organization,BlogPosting,Product,Event. Use the most specific type that’s true; Google’s guidelines ask for “the most specific applicable type and property names defined by schema.org”.@idis “used to uniquely identify node objects”. Give important entities a stable URL-based identifier, likehttps://example.com/#organization, and never change it.@graphis “used to express a graph”. It holds an array of separate nodes in one script, so you can describe the organization, the website, the page and the article side by side, each with its own@id.
Three rules keep these keywords working. @id values are identifiers, not links, so they don’t have to resolve to a page, but using your real domain avoids collisions with anyone else’s. The same entity must use the identical @id string everywhere, down to https and trailing slashes. And @type can take an array when something is genuinely two things, such as a Product that is also a Book.
Nesting vs referencing
There are two ways to connect things: put one object inside another (nesting), or give it an @id and point to that (referencing). Both are valid. Google’s guidelines say it “understands multiple items on a page, whether you nest the items or specify each item individually”, and recommend @id when separate items belong together.
The diagram below compares the two approaches.
Scroll the diagram sideways to see all of it.
Referencing is what turns a site’s markup into a graph. Your organization is described once, with its logo, address and sameAs profiles, and every article, service and page points to it. That’s the pattern behind Organization schema for AI search and Person schema for author entities, and it’s why a clean sameAs list only needs to live in one place (see the sameAs guide).
A referenced node doesn’t have to be on the same page to be meaningful as an identifier, but Google’s guidelines also say to put structured data on the page it describes. The safe pattern is to declare your core Organization and WebSite nodes in a site-wide template so they’re present on every page, and reference them from page-level nodes.
Where does JSON-LD go on a page?
The markup goes in a <script type="application/ld+json"> element, in the <head> or the <body>. Google’s introduction says it is embedded “in the <head> and <body> elements of an HTML page”, and that because the markup isn’t interleaved with visible text, nested data is easier to express.
How the script gets there matters more than where it sits:
- Server-rendered (best). The script is in the HTML the server sends. Every crawler sees it on the first request. Static site generators and server frameworks do this naturally; our Astro SEO guide shows one setup.
- Injected by JavaScript (works for Google). Google says it can read JSON-LD “dynamically injected into the page’s contents, such as by JavaScript code or embedded widgets”. Many AI crawlers don’t run JavaScript, though, as covered in JavaScript rendering and AI crawlers.
- Added by a tag manager (use carefully). Google’s JavaScript structured data guide warns that duplicating page information in Google Tag Manager “increases the risk of having a mismatch between page content and the structured data”.
For product pages there’s an extra reason to render on the server. Google’s product documentation warns that JavaScript-generated Product markup can make Shopping crawls “less frequent and less reliable” for fast-changing prices and availability.
A complete example graph
Here’s a full @graph for a blog post page: the organization, the website, the web page, the article, its author and its breadcrumb, all connected by @id. Replace the example values with your own, and only include properties that are true and visible on the page.
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Organization",
"@id": "https://example.com/#organization",
"name": "Example Co",
"url": "https://example.com/",
"logo": "https://example.com/logo.png"
},
{
"@type": "WebSite",
"@id": "https://example.com/#website",
"url": "https://example.com/",
"name": "Example Co",
"publisher": { "@id": "https://example.com/#organization" }
},
{
"@type": "Person",
"@id": "https://example.com/about/jane-doe/#person",
"name": "Jane Doe",
"url": "https://example.com/about/jane-doe/"
},
{
"@type": "WebPage",
"@id": "https://example.com/blog/json-ld-guide/#webpage",
"url": "https://example.com/blog/json-ld-guide/",
"isPartOf": { "@id": "https://example.com/#website" },
"breadcrumb": { "@id": "https://example.com/blog/json-ld-guide/#breadcrumb" }
},
{
"@type": "BlogPosting",
"@id": "https://example.com/blog/json-ld-guide/#article",
"mainEntityOfPage": { "@id": "https://example.com/blog/json-ld-guide/#webpage" },
"headline": "A practical guide to JSON-LD",
"datePublished": "2026-09-22T09:00:00-04:00",
"dateModified": "2026-09-22T09:00:00-04:00",
"image": ["https://example.com/images/json-ld-16x9.jpg"],
"author": { "@id": "https://example.com/about/jane-doe/#person" },
"publisher": { "@id": "https://example.com/#organization" }
},
{
"@type": "BreadcrumbList",
"@id": "https://example.com/blog/json-ld-guide/#breadcrumb",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Blog", "item": "https://example.com/blog/" },
{ "@type": "ListItem", "position": 2, "name": "A practical guide to JSON-LD" }
]
}
]
}
Wrap it in <script type="application/ld+json"> and </script>. Notice that the Person and Organization are described once and referenced twice. The layered view below shows how the six nodes connect.
Scroll the diagram sideways to see all of it.
Check the rendered page with both official tools: the Schema Markup Validator for schema.org validity and the Rich Results Test for Google eligibility. For the article and breadcrumb parts in detail, see Article schema and breadcrumb schema.
Why Google recommends JSON-LD over Microdata and RDFa
Google recommends it because it’s easiest to maintain, not because it’s worth more. The same introduction calls it “the easiest solution for website owners to implement and maintain at scale (in other words, less prone to user errors)”, and in the same section that “all 3 formats are equally fine for Google, as long as the markup is valid”.
| JSON-LD | Microdata | RDFa | |
|---|---|---|---|
| Where it lives | One script block | Attributes on visible HTML | Attributes on visible HTML |
| Coupled to page layout | No | Yes | Yes |
| Easy to express nested data | Yes | Harder | Harder |
| Survives a redesign | Usually | Often breaks | Often breaks |
| Can be injected by JavaScript | Yes (Google reads it) | Rarely practical | Rarely practical |
| Risk of drifting from visible content | Higher; check it | Lower; it wraps the content | Lower; it wraps the content |
That last row is the honest trade-off. Microdata can’t drift from the page because it’s attached to the visible text. A script block is a separate copy, so a price or an opening time can change on the page while the script stays stale. Google’s guidelines say not to mark up content that isn’t visible, so generate the script from the same data as the page, not typed by hand.
Getting JSON-LD right across a site
The format works best as a system, not a set of snippets. A few decisions made once save a lot of cleanup later.
- Fix your
@idscheme first. Decide the identifiers for your organization, website and each person, and document them. Changing them later splits your entities. - Generate markup from data, not by hand. Pull names, prices, dates and hours from the same source the page uses, so the two can’t disagree.
- Render it on the server so every crawler sees it on the first request.
- Pick one source per entity. Themes, plugins and a schema markup generator can each emit an
Organization. Keep one. - Test by URL after every release with the validator and the Rich Results Test, and watch Search Console’s rich result reports for jumps in invalid items.
This markup is the plumbing for entity SEO: the clearer and more connected the graph, the less work any engine has to do to understand who you are. If your site has grown several overlapping blocks, or you want one graph designed from the start, our schema markup service builds and tests it against the rendered pages.
Frequently asked questions
What is JSON-LD used for?
JSON-LD is used to add structured data to web pages: machine-readable statements about what a page describes, such as an article, a product, a business or a person. Search engines read it to understand the page and to power rich results, and it is the format Google recommends for structured data.
What's the difference between JSON and JSON-LD?
JSON is a general data format with no agreed meaning for its keys. JSON-LD is JSON plus a small set of keywords, such as @context, @type and @id, that tie each key to a shared vocabulary and give things identifiers. Every JSON-LD document is valid JSON, but plain JSON is not linked data.
Where does JSON-LD go in HTML?
Inside a script tag with type application/ld+json, in either the head or the body of the page. Google's documentation says it reads JSON-LD in both places and can also read it when JavaScript injects it into the page, though server-rendered markup is more reliable for other crawlers.
Can a page have more than one JSON-LD script?
Yes. Google understands multiple items on a page whether you nest them or put each in its own block. If separate items describe related things, give them @id values and reference those, so engines know the pieces are connected.
What does @id mean in JSON-LD?
@id gives a thing a unique identifier, usually a URL with a fragment such as https://example.com/#organization. Any other node that references the same @id is talking about the same thing, which lets you describe an entity once and point to it from everywhere else.
Does JSON-LD help with rankings?
Not directly. Google describes structured data as a way to understand pages and enable rich results, and a structured data manual action removes rich result eligibility without affecting ranking. The benefit is clearer understanding and eligibility for enhanced results, not a ranking boost.