The hierarchy of structured data

Structured dataThe concept — any predictable, machine-readable format
Schema markupThe specific vocabulary — schema.org types and properties
JSON-LDThe modern format most sites use to write schema markup

Semantic HTML, meta tags, XML sitemaps and llms.txt are separate but related forms of structured data on the web.

To read the full article which was the inspiration for creating this cheat sheet, you can read it here.

Semantic HTML tags

How to use HTML tags to provide meaning and structure to your content.

Structural / landmark tags

TagUse forExample
<header>Intro block for a page or section (logo, nav, title, byline)<header><h1>Page title</h1></header>
<nav>Primary or secondary navigation links<nav><ul><li><a href="/pricing">Pricing</a></li></ul></nav>
<main>The page's unique content. One per page<main>...core content...</main>
<article>Self-contained content that makes sense on its own (blog post, product card, comment)<article><h2>...</h2><p>...</p></article>
<section>Thematic grouping, usually with its own heading<section aria-labelledby="pricing-h"><h2 id="pricing-h">Pricing</h2>...</section>
<aside>Tangential content (sidebar, pull quote, related links, ads)<aside>Related posts...</aside>
<footer>Footer for a page or section<footer>&copy; 2026 Lumin</footer>

Headings, paragraphs, lists

TagUse forExample
<h1><h6>Document outline. One <h1> per page, nest in order<h1>Main topic</h1><h2>Sub-topic</h2>
<p>Paragraphs<p>Body copy.</p>
<ul>Unordered list, no sequence matters<ul><li>Item</li></ul>
<ol>Ordered list, sequence matters (steps, rankings)<ol><li>Step one</li></ol>
<li>List item<li>Item</li>
<dl> <dt> <dd>Description list: term + definition. Ideal for FAQs, glossaries, key/value specs<dl><dt>What is JSON-LD?</dt><dd>A structured data format.</dd></dl>
<hr>Thematic break between sections<hr>

Tables

TagUse forExample
<table>Tabular or comparison data<table>...</table>
<caption>Table title, first child of <table><caption>Pricing plans</caption>
<thead> <tbody> <tfoot>Row groups<thead><tr><th>Plan</th></tr></thead>
<th scope="col"> / <th scope="row">Header cell, scope defines what it labels<th scope="col">Price</th>
<td>Data cell<td>£49</td>

Text-level semantics

TagUse forExample
<strong>Genuine importance, not just bold styling<strong>Warning:</strong> ...
<em>Stress emphasisThis is <em>the</em> reason.
<mark>Highlighted or relevant-to-context textSearch result: <mark>schema</mark> markup
<abbr title="...">Abbreviation with full expansion<abbr title="Search Engine Optimisation">SEO</abbr>
<dfn>The defining instance of a term<dfn>Structured data</dfn> is machine-readable formatting.
<time datetime="YYYY-MM-DD">Machine-readable date/time<time datetime="2026-09-18">18 Sept 2026</time>
<cite>Title of a referenced creative work<cite>Don't Make Me Think</cite>
<blockquote cite="url">Block quotation from another source<blockquote cite="https://...">Quoted text.</blockquote>
<q>Short inline quotationShe said <q>ship it</q>.
<address>Contact info for the page/article owner<address>Lumin, Brighton, UK</address>
<code> <pre>Inline code / preformatted code block<pre><code>npm install</code></pre>
<small>Fine print, side comments<small>Terms apply</small>

Media

TagUse forExample
<img src alt>Images. alt is mandatory — gives AI/screen readers image context without vision processing<img src="chart.png" alt="Bar chart of SEO traffic by month">
<picture>Responsive images with multiple sources<picture><source srcset="..."><img src="..." alt="..."></picture>
<figure> <figcaption>Self-contained media block with a caption<figure><img ...><figcaption>Fig 1. Traffic growth</figcaption></figure>
<video> <audio>Media embeds. Use <track> for captions/transcripts<video controls><track kind="captions" src="captions.vtt"></video>

Forms

TagUse forExample
<label for="id">Ties label text to a form field, essential for accessibility<label for="email">Email</label><input id="email">
<fieldset> <legend>Groups related fields under one label<fieldset><legend>Contact details</legend>...</fieldset>

ARIA landmarks

Native HTML5 tags already carry most of these roles automatically. Only add an explicit role when you're stuck with<div>-based markup (older CMS, page builder) and can't use the real tag.

RoleNative tag it matchesPurposeExample
role="banner"<header> (page-level)The site header, one per page<header role="banner">
role="navigation"<nav>A navigation block<div role="navigation">...</div>
role="main"<main>The page's main content<div role="main">...</div>
role="complementary"<aside>Tangential content, sidebar<div role="complementary">...</div>
role="contentinfo"<footer> (page-level)The site footer<div role="contentinfo">...</div>
role="search"none nativeA search form or region<div role="search"><input type="search"></div>
role="form"<form> with a nameA form, only counts as a landmark once it has an accessible name<form role="form" aria-label="Newsletter signup">
role="region"<section> with a labelGeneric labelled landmark for content that doesn't fit the others<div role="region" aria-label="Customer stats">

Labelling attributes

Used alongside landmarks and headings:

AttributePurposeExample
aria-label="..."Gives an accessible name when there's no visible heading<nav aria-label="Breadcrumb">
aria-labelledby="id"Points to an existing visible heading as the name<section aria-labelledby="pricing-h">
aria-describedby="id"Points to extra descriptive text (not the name itself)<input aria-describedby="pwd-hint">
aria-hidden="true"Hides purely decorative content from screen readers and AI parsers<span aria-hidden="true">→</span>
aria-current="page"Marks the current item in a set (nav link, breadcrumb, tab)<a href="/pricing" aria-current="page">Pricing</a>

Meta tags

Core

TagPurposeNotes
<title>Page title, shown in SERP and browser tab~50–60 characters displays fully in Google. Longer titles get truncated, but length itself isn't a ranking factor
<meta name="description">SERP snippet~150–160 characters displays fully. Same rule — it's a display limit, not a ranking signal
<meta charset="UTF-8">Character encodingShould be the first tag in <head>. Missing this can break special characters for both browsers and AI parsers
<meta name="viewport">Mobile renderingRequired for mobile-first indexing — a genuine ranking factor

Robots & crawler control

Two tags share the same directive syntax: <meta name="robots">applies to all crawlers, <meta name="googlebot"> is a Google-specific override with the same directives.

DirectiveEffect
index / noindexAllow / block page from search results
follow / nofollowAllow / block crawling of links on the page
max-snippet:-1No limit on text snippet length in search results and AI Overviews
max-snippet:0No text snippet shown
max-image-preview:largeAllow large image thumbnails
max-video-preview:-1No limit on video preview length
nosnippetNo snippet or preview at all
noarchiveDon't store a cached copy
noimageindexDon't index images on the page
unavailable_after: [date]Drop from results after a set date

Example: <meta name="robots" content="index, follow, max-snippet:-1, max-image-preview:large">

AI training opt-out tags — not a recognised standard

TagIntentActual status
<meta name="noai" content="noai">"Don't train generative AI on this content"Community-proposed, not part of any official standard. No confirmed enforcement by major AI crawlers
<meta name="noimageai" content="noimageai">Same, for imagesSame caveat

To actually stop AI crawlers, use robots.txt rather than a meta tag, targeting specific bots:

User-agent: GPTBot
Disallow: /

User-agent: Google-Extended
Disallow: /

User-agent: CCBot
Disallow: /

Google-Extended controls Gemini/AI training only — it doesn't affect normal Google Search indexing. Blocking GPTBot,PerplexityBot or ClaudeBot also blocks those engines from ever citing you.

Canonical & language

TagPurpose
<link rel="canonical" href="...">Declares the preferred URL when duplicate or near-duplicate content exists
<link rel="alternate" hreflang="en-gb" href="...">Signals language/region variants. A signal Google weighs, not a guarantee it'll be honoured
<link rel="alternate" hreflang="x-default" href="...">Fallback for unmatched locales

Open Graph (social previews)

TagPurpose
og:titleTitle shown in the link preview
og:descriptionDescription shown in the preview
og:imagePreview image. Must be an absolute URL
og:image:width / og:image:heightPrevents layout shift when the card renders
og:urlCanonical URL for the shared link
og:typewebsite, article, product, profile, etc. Changes how the platform renders the card
og:site_nameSite name shown next to the preview
og:localeLanguage/region of the content

Twitter/X cards

TagPurpose
twitter:cardsummary or summary_large_image
twitter:title / twitter:description / twitter:imageSame role as Open Graph equivalents, used as fallback if OG tags are missing
twitter:site@handle of the website/brand
twitter:creator@handle of the content author

Technical / other

TagPurpose
<link rel="icon"> / apple-touch-iconFavicons across browsers and devices
<meta name="theme-color">Sets browser UI colour on mobile
<meta name="author">Content author name
<meta http-equiv="refresh">Auto-redirect or refresh. Avoid — harms SEO and UX, rarely justified

A well-built <head>

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Page title | Brand</title>
  <meta name="description" content="Clear, specific summary of the page.">
  <link rel="canonical" href="https://example.com/page">
  <meta name="robots" content="index, follow, max-snippet:-1, max-image-preview:large">

  <meta property="og:title" content="Page title">
  <meta property="og:description" content="Same clear summary, social-friendly.">
  <meta property="og:image" content="https://example.com/og-image.jpg">
  <meta property="og:type" content="article">
  <meta property="og:url" content="https://example.com/page">

  <meta name="twitter:card" content="summary_large_image">
</head>

Schema.org / JSON-LD

A note before the table: schema.org itself has no required properties — every property in the vocabulary is technically optional. "Required" below means required by Google for rich result eligibility. Miss one and the markup is still valid schema, it just won't unlock the enhanced search result.

Common types

TypeUse forGoogle-required propertiesStatus
OrganizationCompany homepage/about, brand identityNone requiredActive Supports Knowledge Panel and logo display
WebSiteHomepageurl; add potentialAction (SearchAction) for the sitelinks search boxActive
Article / BlogPosting / NewsArticleBlog posts, newsNone required (recommended: headline, image, datePublished, dateModified, author)Active
ProductProduct pagesname, image, offers (with price, priceCurrency, availability)Active Splits into Merchant Listing (you sell direct) and Product Snippet (editorial/review pages), each with its own eligibility
AggregateRatingStar ratings, nested inside Product/LocalBusiness/etc.ratingValue, ratingCount or reviewCountActive, must nest inside an eligible parent type
ReviewIndividual reviewsreviewRating, author, nameActive, but only valid nested inside specific types, never standalone. Self-serving reviews are excluded
FAQPageFAQ contentmainEntity (Q&A array)Retired 7 May 2026Schema stays valid, no longer produces a SERP feature
HowToStep-by-step tutorialsname, stepRetired 2023 Same status as FAQPage
QAPageCommunity Q&A with multiple user-submitted answers (forums)mainEntity with an answerCountActive Different job to FAQPage: one official answer vs several community answers
BreadcrumbListAny page with breadcrumbsitemListElement, needs 2+ itemsActive
LocalBusinessLocal business pagesname, addressActive Use the most specific subtype available over genericLocalBusiness
EventEvents, webinarsname, startDate, locationActive
PersonAuthor/team bios, E-E-A-T signalsname (recommended: sameAs, jobTitle, worksFor)Active, a supporting entity rather than its own rich result
VideoObjectVideo contentname, description, thumbnailUrl, uploadDateActive
JobPostingJob listingstitle, description, datePosted, hiringOrganization, jobLocationActive Required for Google Jobs
RecipeRecipe contentname, imageActive
CourseOnline/education coursesname, description, plus hasCourseInstance or offersActive
SoftwareApplicationApps, SaaS toolsname, offers (with price)Active

Validation

Knowledge graphs

A knowledge graph connects your separate schemas into one confirmed web of entities, rather than leaving each type isolated on its own page. This is what gives AI models and Google's own Knowledge Graph confidence about who and what you are.

The two mechanisms that build it:

  1. sameAs: an array of URLs confirming "this is the same entity as the one listed here." Use it onOrganization, Person and Productalike — LinkedIn, Wikidata, Crunchbase, Companies House, industry directories, official social profiles.
  2. @id references: give each entity a stable, unique ID (usually a URL fragment on your own domain) so other schemas can point to it instead of repeating the whole object. This is the actual technique behind "nesting" and "connecting" entities.
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Organization",
      "@id": "https://example.com/#organization",
      "name": "Your business name",
      "url": "https://example.com",
      "logo": "https://example.com/logo.png",
      "sameAs": [
        "https://www.linkedin.com/company/yourbusiness",
        "https://www.wikidata.org/wiki/Qxxxxxxx",
        "https://www.crunchbase.com/organization/yourbusiness"
      ]
    },
    {
      "@type": "WebSite",
      "@id": "https://example.com/#website",
      "url": "https://example.com",
      "name": "Your business name",
      "publisher": { "@id": "https://example.com/#organization" }
    },
    {
      "@type": "Person",
      "@id": "https://example.com/#author-jane",
      "name": "Jane Doe",
      "sameAs": ["https://www.linkedin.com/in/janedoe"],
      "worksFor": { "@id": "https://example.com/#organization" }
    },
    {
      "@type": "Article",
      "headline": "Article title",
      "author": { "@id": "https://example.com/#author-jane" },
      "publisher": { "@id": "https://example.com/#organization" }
    }
  ]
}

Every entity is defined once, then referenced everywhere it applies. AProduct can point to the same Organization anArticle does, which points to the same WebSite, and so on.

A sensible starting graph for most sites:Organization + WebSite + Person(for each author), connected by @id, before going deeper into Product- or Article-level graphs.

Other structured data on the web

FormatPurposeNotes
XML sitemapList of every indexable page + metadata (last modified, priority)Submit via Search Console. Essential for discovery, not a ranking factor itself
RSS/Atom feedStructured feed of updates (blog posts, releases)Used by feed readers and some AI crawlers to spot fresh content
robots.txtSite-wide crawl rules by botDifferent from meta robots: this is site/directory-level. Can target specific bots: GPTBot, Google-Extended, CCBot, PerplexityBot, ClaudeBot
llms.txtMarkdown file at the root, plain-language summary of the site for AI agentsSee reality check below

Reality checks and rules

  • Google's own guidance: no special markup is required for AI Overviews or AI Mode. It uses standard Search ranking. Don't chunk content into fragments "for AI" — write normal paragraphs and headings for people. Writing separate content variants targeted at AI risks Google's scaled content abuse spam policy.
  • FAQPage and HowTo rich results are dead in Google Search. HowTo was retired in 2023, FAQ followed on 7 May 2026. The schema types are still valid and Google still parses them to understand a page, but neither produces a SERP feature any more for any site.
  • Google prunes rich result types regularly. January 2026 removed several niche types (Practice Problems, Nutrition Facts, Nearby Offers, Local Bikeshare Station Status). Check current eligibility before investing heavily in a less common type.
  • Unused schema doesn't need panic-removing. Google has confirmed structured data that isn't triggering a feature causes no harm to Search — it just has no visible effect.
  • Other engines (ChatGPT, Perplexity, Claude) do actively favour extractable structure: lists, tables, definition blocks. This helps those engines and doesn't hurt Google, since it's just good content organisation.
  • Character limits on title/meta description are display truncation points, not ranking rules.
  • hreflang is a signal search engines weigh, not a directive they must obey.
  • JavaScript-only rendering is the single biggest blocker. If content only appears after client-side JS runs, most AI crawlers never see it, regardless of how good the tags are. Structured data must also be present in the initial HTML, not injected client-side, for Google Shopping crawls specifically.
  • Schema accuracy matters more than coverage. Markup that doesn't match visible page content (price, date, rating) risks a manual action, not just lost rich results.
  • BreadcrumbList needs at least two items to be considered valid.
  • Review rich results only attach to specific entity types (Product, LocalBusiness, Recipe, Event, Book, Movie, SoftwareApplication, etc.), never as a standalone page, and self-serving reviews are excluded.
  • llms.txt has no proven ranking or citation effect. Google has stated it has no bearing on rankings or AI Overviews, and large-scale tracking found no meaningful adoption or citation correlation. The one genuine use case is developer docs and API tools, where coding assistants use it as an efficient entry point.