The JSON search engines actually read
Every rich result you've seen in Google — star ratings under a recipe, an FAQ accordion right in the search results, a breadcrumb trail instead of a raw URL — comes from a block of JSON quietly embedded in the page's HTML. That JSON is JSON-LD (JSON for Linking Data), and the vocabulary it uses is almost always schema.org. This isn't a proprietary Google format — it's a W3C-backed standard, and once you can read it, you can read the SEO markup on any site's page source.
What it looks like on a real page
JSON-LD sits inside a <script> tag with a special type, invisible to visitors but fully readable by crawlers:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Recipe",
"name": "Classic Margherita Pizza",
"author": { "@type": "Person", "name": "Ada Lovelace" },
"prepTime": "PT20M",
"cookTime": "PT15M",
"recipeYield": "4 servings",
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.8",
"reviewCount": "412"
}
}
</script>Two fields anchor every JSON-LD block: `@context` tells parsers which vocabulary you're using (almost always https://schema.org), and `@type` names the schema.org type this object represents — Recipe, Product, Article, FAQPage, and hundreds more are defined at schema.org.
The types that actually drive rich results
Google supports dozens of schema.org types for rich results, but a handful cover most sites:
| Type | What it powers | Key fields |
|---|---|---|
Organization | Knowledge panel, logo in search | name, url, logo |
BreadcrumbList | Breadcrumb trail instead of a raw URL | itemListElement (ordered ListItems) |
FAQPage | Expandable FAQ snippets in results | mainEntity (array of Question/Answer) |
Product | Price, availability, star rating in results | offers, aggregateRating |
Article / BlogPosting | Headline, author, date in results | headline, author, datePublished |
HowTo | Numbered step-by-step rich result | step (ordered HowToSteps) |
SoftwareApplication | App info card | applicationCategory, offers |
A minimal FAQPage — the exact shape behind FAQ accordions ranking with extra visible space in search results:
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "Is JSON-LD visible to site visitors?",
"acceptedAnswer": { "@type": "Answer", "text": "No — it lives in a script tag and is never rendered." }
}
]
}Linking objects together with @id
Real sites don't emit one isolated blob per page — they reference a shared Organization or WebSite object across every page using an @id, so a crawler can tell that the "JSONKit" mentioned on ten different pages is the same entity:
{
"@context": "https://schema.org",
"@type": "Organization",
"@id": "https://example.com/#organization",
"name": "Example Inc",
"url": "https://example.com"
}Any other JSON-LD block on the site can then reference "publisher": { "@id": "https://example.com/#organization" } instead of repeating the whole object — the same normalization idea as a foreign key in a database, expressed in JSON.
Generating it in code
In a React/Next.js app, JSON-LD is just a script tag with stringified JSON — no special library required:
function ArticleJsonLd({ title, author, datePublished }) {
const data = {
"@context": "https://schema.org",
"@type": "Article",
headline: title,
author: { "@type": "Person", name: author },
datePublished,
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }}
/>
);
}The one real gotcha: escape untrusted content. If title or author ever comes from user input, a value like </script><script>alert(1)</script> breaks out of the block — JSON.stringify alone doesn't escape </. Replace < with \u003c before injecting, or use a templating layer that does it for you.
Validating your structured data
Two checks matter before you ship JSON-LD: is it valid JSON, and does it satisfy the schema.org type's expected shape? Malformed JSON-LD is silently ignored by Google rather than erroring, so it's easy to ship broken markup and never notice.
- Paste the block into JSONKit's JSON Validator to catch syntax errors first.
- Run the live page through Google's Rich Results Test to confirm Google actually recognizes the type and fields.
- For a reusable content shape, sketch it as a JSON Schema so every page on your site emits a consistent structure.