Command Palette

Search for a command to run...

Hectal
PHASE 6Intermediate ~20 min· topic 6 of 7

Topic 6.6

Structured Data

In one line

Structured data is a JSON-LD block that describes the page's content in schema.org vocabulary (a product with a price, a recipe with a cooking time), so search engines can understand it exactly and may show rich results like stars and prices.

Think of it like this

A form at the doctor's office. You could write your details as a story ("I'm Ravi, I was born in March 1990..."), but the receptionist prefers a form with labelled boxes: Name, Date of birth, Phone. Your web page is the story; structured data is the form, filled in with labelled boxes a machine can read without guessing.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Structured data
Facts about a page written in a fixed, labelled format that machines can read exactly.
schema.org
A shared dictionary of types (Product, Recipe) and properties (price, author) used for structured data.
JSON-LD
Structured data written as JSON inside <script type="application/ld+json">.
@context
The JSON-LD key that says which vocabulary you are using, usually https://schema.org.
@type
The JSON-LD key that says what kind of thing this is, like Product or Recipe.
Property
One labelled fact about a thing, like its name or price.
Rich result
A search result with extras like stars, prices or cooking times.
Microdata
An older way to add structured data with itemprop attributes on normal HTML elements.
Manual action
A penalty a Google reviewer applies to a site for breaking its rules.

Step by step

01Start with the visible page

Structured data describes what is already on the page. Here the product page shows a name, a picture, a price, stock status and a rating.

bag.htmlwhole filehtml
<h1>Blue Cotton School Bag</h1>
<p class="price">₹899</p>
<p>In stock</p>
<p>★ 4.6 (128 reviews)</p>

02Pick the type

Look it up on schema.org: this is a Product. Google's documentation for product snippets lists which properties are required and recommended.

03Write the JSON-LD

Same facts, in labelled boxes. Prices are plain numbers (or strings of digits) with a separate priceCurrency in ISO 4217 codes (INR, USD); availability uses a schema.org URL.

bag.htmlwhole filehtml
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Blue Cotton School Bag",
  "image": "https://bagbazaar.example/img/blue-bag.jpg",
  "offers": {
    "@type": "Offer",
    "price": "899",
    "priceCurrency": "INR",
    "availability": "https://schema.org/InStock"
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.6",
    "reviewCount": "128"
  }
}
</script>
Write the JSON-LDdiagram
Rendering diagram…

04Add breadcrumbs

A BreadcrumbList tells search engines where the page sits in your site, so the result can show BagBazaar › School › Bags instead of a long URL. Positions start at 1.

bag.htmlwhole filejson
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    { "@type": "ListItem", "position": 1, "name": "School", "item": "https://bagbazaar.example/school" },
    { "@type": "ListItem", "position": 2, "name": "Bags", "item": "https://bagbazaar.example/school/bags" }
  ]
}

05Test it

Paste the URL or the code into the Rich Results Test. It lists detected items ("Product snippets", "Breadcrumbs"), errors that make an item ineligible, and warnings about missing recommended properties.

Try it yourself

  1. 1

    Change the price

    In the first example, change the price to 799 in the JSON-LD only. Run it. The rich line now disagrees with the visible page: that mismatch is exactly what Google's guidelines forbid. Fix both.

  2. 2

    Out of stock

    Change availability to https://schema.org/OutOfStock. Predict the fourth console line, then run.

  3. 3

    Add a level

    In the second example, add a fourth link Backpacks to https://bagbazaar.example/school/bags/backpacks. Predict its position number before running.

Code & diagrams

Read structured data like a search engine New tab

A crawler parses the JSON exactly like this. The grey line under the fake result is what a rich result might add.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

Type: Product
Name: Blue Cotton School Bag
Price: 899 INR
In stock: true
Generate breadcrumb JSON-LD from the page's own links New tab

Building JSON-LD from the same data as the visible page keeps the two in sync. On a real site, do this on the server or at build time so every crawler sees it.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

1 Home https://bagbazaar.example/
2 School https://bagbazaar.example/school
3 Bags https://bagbazaar.example/school/bags
JSON-LD blocks in the head: 1
The same product in Microdata (the older way)html
<div itemscope itemtype="https://schema.org/Product">
  <h1 itemprop="name">Blue Cotton School Bag</h1>
  <div itemprop="offers" itemscope itemtype="https://schema.org/Offer">
    <span itemprop="priceCurrency" content="INR">₹</span><span itemprop="price" content="899">899</span>
    <link itemprop="availability" href="https://schema.org/InStock">In stock
  </div>
</div>

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Invalid JSON hides everything

In the first example, add a comma after the last property ("reviewCount": "128" }, before the closing }).

terminal
$ Console
── what you'll see ──
Uncaught SyntaxError: Expected double-quoted property name in JSON at position ... (Rich Results Test: "Parsing error: Missing '}' or object member name")

Break #2

User text that closes the script tag

On the server, build JSON-LD with JSON.stringify(review) where a user's review text contains </script>.

terminal
$ the page
── what you'll see ──
The JSON-LD block ends early; the rest of the review text spills into the page as HTML (a cross-site scripting risk).

Myth vs fact

Myth

Structured data improves your ranking.

Fact

Google says it's not a general ranking factor. It helps search engines understand the page and makes it eligible for rich results, which can raise clicks.

Myth

Valid markup guarantees stars in search results.

Fact

Valid markup makes a page eligible. Google decides per search whether to show a rich result, and some types (FAQ, HowTo) are now heavily limited.

Myth

You can mark up things that aren't on the page.

Fact

Markup must describe visible, true content. Hidden or misleading markup breaks the guidelines and can lead to a manual action.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    Google supports JSON-LD injected by JavaScript (it renders pages), but other consumers (Bing for some features, social apps, many AI crawlers) may only read the server HTML. Server-render it.

  • ▸

    Use @id with stable URLs (https://example.com/#organization) to connect entities across pages: an Article's publisher can point to the site's Organization instead of repeating it. This builds a consistent entity graph.

  • ▸

    Dates use ISO 8601 (2026-10-05, durations like PT20M for 20 minutes in Recipe.cookTime). Wrong formats are the most common Rich Results Test errors after missing required fields.

  • ▸

    Next.js's documentation recommends exactly the < → \u003c replacement when rendering JSON-LD with dangerouslySetInnerHTML; Hectal's <JsonLd> component follows the same idea.

Remember this

  1. 1

    Search engines read your text and guess what it means. Structured data removes the guessing: it states facts in a shared vocabulary. That vocabulary is schema.org, a project started in 2011 by Google, Microsoft, Yahoo and Yandex. It defines types (Product, Recipe, Article, Event, Organization, BreadcrumbList, Course...) and the properties each type can have (name, price, author, startDate...).

  2. 2

    The recommended format is JSON-LD (JSON for Linked Data): a <script type="application/ld+json"> block containing JSON. The browser doesn't run it, because its type isn't JavaScript; it's data for machines. It can go in the head or the body. "@context": "https://schema.org" says which vocabulary you use, "@type" says what the thing is, and the other keys are its properties.

  3. 3

    Properties can hold other typed things: a Product has offers, which is an Offer with price and priceCurrency, and aggregateRating, an AggregateRating with ratingValue and reviewCount. This nesting is how you describe real relationships. @id gives a thing a unique URL-like name so other blocks can refer to it, and @graph holds several things in one block.

  4. 4

    Rich results are search results with extras: star ratings, prices and stock, recipe cooking times, event dates, breadcrumb trails instead of URLs. Google decides when to show them; valid markup makes a page eligible, not guaranteed. Google's support changes over time: since 2023, FAQ rich results appear only for well-known government and health sites, and HowTo rich results were removed. Check Google's Search Gallery for what is currently supported.

  5. 5

    The golden rule: mark up only what is visible on the page and true. A 5-star rating in JSON-LD that doesn't appear on the page, or a fake price, breaks Google's guidelines and can earn a manual action (a penalty that removes your rich results). The older formats Microdata (itemscope, itemtype, itemprop attributes woven into the HTML) and RDFa still work, but JSON-LD is easier to keep separate from your markup.

  6. 6

    Test with Google's Rich Results Test (which features your page qualifies for, and errors) and the Schema Markup Validator at validator.schema.org (checks against the full vocabulary). After launch, Search Console's enhancement reports show errors across the whole site. Hectal itself adds Course and breadcrumb JSON-LD to every course and topic page.

Explain it without notes

01

What is structured data, and why is JSON-LD the recommended format?

02

What are rich results, and does valid markup guarantee them?

03

Why must structured data match the visible page?

04

How do you safely embed user-provided text in a JSON-LD block?

Practice

01

Write a JSON-LD Recipe for "Egg-free pancakes" by Asha, ready in 20 minutes (cook time 10 minutes), making 8 pancakes, with three ingredients.

02

Write a function toJsonLd(data) that returns a string safe to put inside a <script type="application/ld+json">. Test it with { name: "</script>hi" } and log whether the result contains </script.

Trade-offs

  • ↔

    JSON-LD is separate from the visible HTML, which makes it easy to maintain but also easy to let drift out of sync with the page; generating both from the same data solves that.

  • ↔

    Marking up every possible type costs build time and testing; focus on the types that have rich results for your kind of site (products, recipes, articles, events, breadcrumbs).

Done when you can

  • I can write a JSON-LD block with @context, @type and properties.

  • I can nest types, like an Offer inside a Product.

  • I can add a BreadcrumbList.

  • I mark up only visible, true content.

  • I can test markup with the Rich Results Test and Schema Markup Validator.

  • I escape < when embedding JSON-LD built from user data.