JSON-LD structured data for AI search
Which schema.org types AI engines actually read, where to put the JSON-LD, and the seven schemas that earn the most AEO points — copy-pasteable templates included.
Structured data is the cheapest AEO win available. A 30-line block of JSON-LD in your <head> is worth 6 of 100 points in the AEO Site Checker rubric — and another 3 points come from doing it well (filling in author, sameAs, dateModified).
This guide covers what AI engines actually read, which schemas they care about, and the gotchas that make a perfectly valid JSON-LD block silently useless.
Why JSON-LD specifically
You have three options for structured data: microdata, RDFa, and JSON-LD. AI search engines almost universally prefer JSON-LD because:
- It lives in
<script type="application/ld+json">blocks in your<head>— easy for the parser to find without walking the DOM. - It’s a single, self-contained JSON object — no entity resolution across attributes.
- Google has been recommending it as the primary format since 2017, so the open-web tooling has converged.
Every AI engine we’ve tested — ChatGPT Search, Perplexity, Claude, Google’s AI Overviews — reads JSON-LD first and falls back to microdata only when JSON-LD is absent.
The seven schemas that earn the most points
In order of impact:
1. Article (for blog posts, news, long-form content)
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "How to write an llms.txt",
"description": "A 6-minute guide to the format, rules, and a copy-pasteable template.",
"datePublished": "2026-04-15T00:00:00Z",
"dateModified": "2026-05-03T00:00:00Z",
"author": {
"@type": "Person",
"name": "Jane Doe",
"url": "https://example.com/about",
"sameAs": [
"https://twitter.com/janedoe",
"https://github.com/janedoe",
"https://www.linkedin.com/in/janedoe"
]
},
"publisher": {
"@type": "Organization",
"name": "Example Co",
"url": "https://example.com",
"logo": {
"@type": "ImageObject",
"url": "https://example.com/logo.png"
}
},
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://example.com/blog/llms-txt"
}
}
</script>
The fields that really matter for AEO:
authorwithsameAs— provenance. The model cross-references the listed profiles to gauge whether the author is a real, identifiable person. This earns theauthor_provenancecheck (3 pts).dateModified— freshness. If your article was last updated in 2022, AI engines silently de-prioritize it. SettingdateModifiedto a recent date — and meaning it — earns thedate_modifiedcheck (2 pts).mainEntityOfPage.@id— the canonical URL. This anchors the entity to a specific page so the model doesn’t confuse it with similar articles.
2. Organization (for the homepage)
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "Example Co",
"url": "https://example.com",
"logo": "https://example.com/logo.png",
"description": "What the company does, in one sentence.",
"sameAs": [
"https://twitter.com/examplecom",
"https://github.com/examplecom",
"https://www.linkedin.com/company/examplecom"
],
"contactPoint": {
"@type": "ContactPoint",
"contactType": "customer support",
"email": "support@example.com"
}
}
</script>
The sameAs array is the entity-resolution mechanism. AI engines use it to merge “Example Co” mentions across the web into a single entity. Skip it and you fragment your authority.
3. FAQPage (any page with Q&A blocks)
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "What is AEO?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Answer Engine Optimization is..."
}
},
{
"@type": "Question",
"name": "How does the score work?",
"acceptedAnswer": {
"@type": "Answer",
"text": "27 weighted checks across 5 categories..."
}
}
]
}
</script>
FAQPage is the highest-leverage schema for AI citation. The model treats each Question / Answer pair as a self-contained, citable unit — exactly the granularity it needs. If you have an FAQ section anywhere on your site, mark it up.
4. LocalBusiness (service businesses, retail, restaurants)
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"name": "Morrison Plumbing",
"image": "https://example.com/storefront.jpg",
"url": "https://example.com",
"telephone": "+1-704-555-0142",
"priceRange": "$$",
"address": {
"@type": "PostalAddress",
"streetAddress": "123 Main St",
"addressLocality": "Charlotte",
"addressRegion": "NC",
"postalCode": "28202",
"addressCountry": "US"
},
"geo": {
"@type": "GeoCoordinates",
"latitude": 35.2271,
"longitude": -80.8431
},
"openingHoursSpecification": [
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
"opens": "08:00",
"closes": "18:00"
}
],
"areaServed": {
"@type": "City",
"name": "Charlotte"
}
}
</script>
If you operate a local business, this single schema is the difference between being mentioned by name when someone asks “best plumbers in Charlotte” versus being a generic “I don’t have specific recommendations” response.
5. Person (about pages, author pages)
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Person",
"name": "Jane Doe",
"url": "https://example.com/about",
"image": "https://example.com/headshot.jpg",
"jobTitle": "Plumbing Technician",
"worksFor": {
"@type": "Organization",
"name": "Morrison Plumbing"
},
"sameAs": [
"https://twitter.com/janedoe",
"https://www.linkedin.com/in/janedoe"
]
}
</script>
6. Product (e-commerce, SaaS pricing pages)
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Pro Plan",
"description": "Everything in Free, plus team accounts and audit history.",
"brand": { "@type": "Brand", "name": "Example Co" },
"offers": {
"@type": "Offer",
"price": "29.00",
"priceCurrency": "USD",
"availability": "https://schema.org/InStock"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.7",
"reviewCount": "412"
}
}
</script>
7. BreadcrumbList (any page deeper than root)
<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" },
{ "@type": "ListItem", "position": 3, "name": "Article title", "item": "https://example.com/blog/article" }
]
}
</script>
BreadcrumbList is small, easy to generate, and gives the model a sense of site hierarchy that helps with attribution.
Common gotchas
Gotcha 1: Multiple JSON-LD blocks > one giant block
It’s fine — and often clearer — to ship multiple <script type="application/ld+json"> blocks per page. The crawler concatenates them. Use one per logical entity (Organization block, FAQPage block, BreadcrumbList block) rather than trying to nest everything inside a single object.
Gotcha 2: Don’t lie
If your aggregateRating is 4.9 but you have 3 reviews, the model will eventually figure that out and downweight everything else on the page. Match the JSON-LD to what’s visible on the page.
Gotcha 3: dateModified has to actually mean something
If dateModified is “now” on every page load (because your CMS regenerates it dynamically), AI engines learn to ignore it. Set it to the actual last-edit timestamp.
Gotcha 4: Validate before shipping
Use validator.schema.org and Google’s Rich Results Test. Both will catch typos in @type, missing required fields, and invalid date formats. The AEO Site Checker also flags obvious problems but doesn’t validate the full schema graph.
Gotcha 5: It has to be in the server-rendered HTML
If you ship the JSON-LD via useEffect after hydration, AI crawlers won’t see it. The block must be present in the raw HTML response — that means rendering it server-side (Astro, Next.js SSR/SSG, plain server-rendered templates) or generating it at build time.
How the AEO Site Checker scores it
Three checks contribute:
| Check | Weight | What it looks for |
|---|---|---|
json_ld_types | 6 | At least one valid @context: schema.org block with a recognized @type. Bonus for FAQPage, Article, Organization, LocalBusiness, Person, Product, RealEstateListing. |
author_provenance | 3 | An author object on Article schema with at least one sameAs link to a profile (LinkedIn, GitHub, ORCID, Twitter, etc.). |
date_modified | 2 | A dateModified field within the last 12 months. |
Maxing all three is 11 of 100 points — a meaningful chunk for a single afternoon’s work.
Further reading
- What is /llms.txt
- Robots.txt for AI crawlers
- AEO Site Checker whitepaper
- schema.org Full Hierarchy
- Google’s structured data guidelines
Ready to score your site? Run an audit →