JSON-LD (JavaScript Object Notation for Linked Data) is the recommended format for adding structured data to web pages. It uses standard JSON syntax with a few special keywords to connect your data to the Schema.org vocabulary.
Why JSON-LD Is Preferred
Three formats exist for structured data on the web: JSON-LD, Microdata, and RDFa. JSON-LD is the dominant choice for several reasons.
Separation from HTML. JSON-LD lives in a <script> tag, completely separate from your visible markup. You can add, modify, or remove structured data without touching a single line of your HTML template. Microdata and RDFa require you to weave attributes into your existing HTML elements.
Easy to generate. Any backend system can produce JSON. If your content comes from a CMS or database, you can serialize structured data from your data models directly. No HTML manipulation required.
Recommended by Google. Google explicitly recommends JSON-LD over other formats in their documentation. Their tooling and examples default to JSON-LD.
Human-readable. JSON is a familiar format for developers. If you can read a JSON API response, you can read a JSON-LD block.
The Anatomy of a JSON-LD Block
Every JSON-LD block has the same basic structure:
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Understanding Structured Data",
"datePublished": "2026-01-15",
"author": {
"@type": "Person",
"name": "Alex Chen"
}
}
Let’s break down each part.
@context
"@context": "https://schema.org"
This tells the parser which vocabulary to use for interpreting the properties. Almost all web structured data uses https://schema.org as the context. You include this once at the top level. Nested objects inherit the context from their parent.
@type
"@type": "Article"
This declares the Schema.org type of the entity you are describing. It corresponds to a type page on schema.org (e.g., schema.org/Article). Every JSON-LD object should have a @type.
Properties
The remaining key-value pairs are Schema.org properties. Each key (like headline, datePublished, author) maps to a property defined on the Schema.org type page for Article.
Property values can be:
- Strings —
"headline": "Understanding Structured Data" - Numbers —
"wordCount": 1500 - Dates —
"datePublished": "2026-01-15"(ISO 8601 format) - Booleans —
"isAccessibleForFree": true - Nested objects — another JSON-LD object with its own
@type - Arrays — a list of values or objects
Where to Place JSON-LD in HTML
Add JSON-LD inside a <script> tag with the type application/ld+json. Place it in the <head> of your document:
<!DOCTYPE html>
<html>
<head>
<title>Understanding Structured Data</title>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Understanding Structured Data",
"datePublished": "2026-01-15"
}
</script>
</head>
<body>
<!-- page content -->
</body>
</html>
Placement in <head> is conventional and recommended, but JSON-LD blocks in <body> are also valid. Google will parse them regardless of position.
Nesting Objects
Many Schema.org properties expect objects rather than simple values. You nest them directly:
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Wireless Noise-Cancelling Headphones",
"brand": {
"@type": "Brand",
"name": "SoundMax"
},
"offers": {
"@type": "Offer",
"price": "249.99",
"priceCurrency": "USD",
"availability": "https://schema.org/InStock",
"seller": {
"@type": "Organization",
"name": "TechStore"
}
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.6",
"reviewCount": "892"
}
}
Nested objects do not need their own @context. They inherit it from the top-level object.
There is no hard limit on nesting depth, but keep it practical. Two or three levels deep covers most real-world cases.
Using @id for Linking
The @id keyword assigns a unique identifier to an entity. This allows you to reference the same entity from multiple places without duplicating its data.
{
"@context": "https://schema.org",
"@type": "Organization",
"@id": "https://example.com/#organization",
"name": "Example Corp",
"url": "https://example.com"
}
You can then reference this entity elsewhere using just its @id:
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Our Latest Update",
"publisher": {
"@id": "https://example.com/#organization"
}
}
The @id value is typically a URL with a fragment identifier (the # portion). It does not need to resolve to an actual page. It serves as a unique key within your structured data.
Multiple JSON-LD Blocks on One Page
You can include more than one JSON-LD block on a single page. This is common when a page contains multiple distinct entities.
For example, a page might have both a BreadcrumbList and an Article:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://example.com"
},
{
"@type": "ListItem",
"position": 2,
"name": "Blog",
"item": "https://example.com/blog"
}
]
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Getting Started with JSON-LD",
"datePublished": "2026-02-10",
"author": {
"@type": "Person",
"name": "Jordan Rivera"
}
}
</script>
Alternatively, you can combine multiple entities in a single block using the @graph keyword:
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://example.com"
}
]
},
{
"@type": "Article",
"headline": "Getting Started with JSON-LD",
"datePublished": "2026-02-10"
}
]
}
Both approaches are valid. Using @graph is cleaner when entities reference each other via @id.
Common Data Types
JSON-LD uses standard JSON types, but some Schema.org properties expect specific formats:
Dates and Times
Use ISO 8601 format. Dates are YYYY-MM-DD. Date-times include the time and optionally a timezone:
"datePublished": "2026-03-07"
"startDate": "2026-04-15T09:00:00-05:00"
Durations
Use ISO 8601 duration format. PT prefix means “period of time”:
"cookTime": "PT30M"
"duration": "PT1H15M"
PT30M means 30 minutes. PT1H15M means 1 hour and 15 minutes.
URLs
Use full absolute URLs:
"url": "https://example.com/product/headphones"
"image": "https://example.com/images/headphones.jpg"
Enumerated Values
Some properties expect a Schema.org enumeration value:
"availability": "https://schema.org/InStock"
"itemCondition": "https://schema.org/NewCondition"
These are always full Schema.org URLs.
Validation
After writing JSON-LD, validate it. Two primary tools:
- Google Rich Results Test — tests whether your structured data qualifies for Google rich results. Available at
search.google.com/test/rich-results. - Schema Markup Validator — validates your markup against the Schema.org specification without Google-specific rules. Available at
validator.schema.org.
Test early and test often. A missing comma or incorrect nesting can silently break your structured data.