Microdata is an HTML syntax for attaching structured data to the elements that already display a page’s content, using five attributes: itemscope, itemtype, itemprop, itemid, and itemref. It was the format search engines pointed publishers to when schema.org launched in 2011, and it remains widely deployed and fully parsed by Google, though JSON-LD is now the recommended format.
Standards status
Microdata is part of the WHATWG HTML living standard, defined as a normative section alongside the rest of HTML. The W3C published its own Microdata specification in parallel, but that document was discontinued and republished as a Working Group Note rather than a Recommendation. So Microdata is a standard, in WHATWG HTML.
One part of the original design never shipped. The specification defined a DOM API, including document.getItems(), so that scripts could read microdata items the way they read the DOM. No browser implemented it in a form that survived. Microdata is therefore purely a serialization: consumers parse the HTML, and nothing in the page itself uses it.
The five attributes
itemscope is a boolean attribute that declares a new item. The element and its descendants describe one thing.
<div itemscope>…</div>
itemtype gives the item’s type as an absolute URL, which also supplies the vocabulary.
<div itemscope itemtype="https://schema.org/Product">…</div>
itemprop names a property of the nearest enclosing item.
<h1 itemprop="name">Neo4j Graph Database</h1>
itemid gives the item a global identifier so consumers can recognize it across pages. It is only meaningful when itemtype is present.
<div itemscope itemtype="https://schema.org/Book"
itemid="urn:isbn:9780262527910">…</div>
itemref pulls in properties from elements elsewhere in the document by ID, for cases where the markup cannot be nested.
<div itemscope itemtype="https://schema.org/Product" itemref="shared-brand">…</div>
How the vocabulary resolves
The itemtype URL does two jobs. It states the item’s type, and it sets the vocabulary against which every itemprop inside that item is interpreted. With,itemtype="https://schema.org/Product", an itemprop="sku" resolves to https://schema.org/sku, following schema.org’s convention that a property name appended to the vocabulary URL yields the property IRI.
Two consequences follow. Property names are case-sensitive and must match schema.org exactly (addressLocality, not addresslocality). And unlike RDFa, there is no prefix mechanism, so mixing vocabularies inside one item is not idiomatic. An itemprop whose value is itself an absolute URL is the only escape, and consumer support for it is uneven.
A worked example
The following marks up a product page with a nested Offer and an AggregateRating.
<div itemscope itemtype="https://schema.org/Product"
itemid="https://example.com/products/graph-db#product">
<h1 itemprop="name">Atlas Graph Server</h1>
<img itemprop="image" src="https://example.com/img/atlas.png" alt="Atlas Graph Server">
<p itemprop="description">A triple store with a SPARQL 1.1 endpoint.</p>
<span itemprop="sku">ATL-2026</span>
<div itemprop="offers" itemscope itemtype="https://schema.org/Offer">
<span itemprop="priceCurrency" content="USD">$</span>
<span itemprop="price" content="1200.00">1,200</span>
<link itemprop="availability" href="https://schema.org/InStock">
<span>Ships from
<span itemprop="seller" itemscope itemtype="https://schema.org/Organization">
<span itemprop="name">Atlas Data</span>
</span>
</span>
<meta itemprop="priceValidUntil" content="2026-12-31">
</div>
<div itemprop="aggregateRating" itemscope itemtype="https://schema.org/AggregateRating">
Rated <span itemprop="ratingValue">4.6</span>
by <span itemprop="reviewCount">128</span> reviewers
</div>
</div>
Extracted, that yields the following triples.
@prefix schema: <https://schema.org/> .
<https://example.com/products/graph-db#product>
a schema:Product ;
schema:name "Atlas Graph Server" ;
schema:image <https://example.com/img/atlas.png> ;
schema:description "A triple store with a SPARQL 1.1 endpoint." ;
schema:sku "ATL-2026" ;
schema:offers [
a schema:Offer ;
schema:priceCurrency "USD" ;
schema:price "1200.00" ;
schema:availability <https://schema.org/InStock> ;
schema:priceValidUntil "2026-12-31" ;
schema:seller [
a schema:Organization ;
schema:name "Atlas Data"
]
] ;
schema:aggregateRating [
a schema:AggregateRating ;
schema:ratingValue "4.6" ;
schema:reviewCount "128"
] .
The Product is a named subject because of itemid. The Offer, Organization, and AggregateRating are blank nodes, written [ … ], because they declared itemscope and itemtype without an itemid.
Nested items
An element with both itemprop and itemscope does two things at once: it becomes the value of that property on the outer item, and it starts a new item that owns everything inside it. That single rule produces the whole nesting model, and it is how a Product gets an Offer and the Offer gets a seller without repeating identifiers.
Nesting is scoped strictly by the DOM. An itemprop belongs to the nearest ancestor with itemscope, with no exceptions, which makes Microdata easy to reason about but inflexible when the layout doesn’t match the data structure.
The itemref escape hatch
itemref exists when a property’s markup cannot be a descendant of the item, usually because the design puts it elsewhere on the page. It takes a space-separated list of element IDs, and the properties on those elements and their descendants are treated as if they were inside the item.
<div itemscope itemtype="https://schema.org/Product" itemref="brand-block price-block">
<h1 itemprop="name">Atlas Graph Server</h1>
</div>
<footer id="brand-block" itemprop="brand" itemscope itemtype="https://schema.org/Brand">
<span itemprop="name">Atlas Data</span>
</footer>
<aside id="price-block" itemprop="offers" itemscope itemtype="https://schema.org/Offer">
<span itemprop="price" content="1200.00">1,200</span>
<meta itemprop="priceCurrency" content="USD">
</aside>
One referenced block can be shared by several items, which is the usual reason to reach for it: a comparison table of ten products carrying the same brand. Use it sparingly. It creates action at a distance between two parts of a template, and a refactor that renames an ID breaks the item silently.
How values are read from elements
Microdata takes the property value from the element type, not always from its text. Getting this wrong is the most common source of malformed data.
| Element | Value comes from |
|---|---|
Most elements (span, div, p, h1) | Text content |
a, area, link | href |
img, audio, video, source, embed, iframe, track | src |
object | data |
time | datetime, falling back to text content |
meta | content (the element displays nothing) |
data | value |
Any element with a content attribute | content, overriding the text |
The pattern that follows: <meta itemprop="…" content="…"> for values with no visible counterpart, <time itemprop="datePublished" datetime="2026-09-08">September 8, 2026</time> for dates, <link itemprop="availability" href="https://schema.org/InStock"> for enumeration values, and a content attribute whenever the displayed string is formatted for humans (1,200 displayed, 1200.00 in content).
Microdata vs JSON-LD
JSON-LD expresses the same triples in a <script type="application/ld+json"> block. Google parses Microdata, RDFa, and JSON-LD, and states that all three are eligible for rich results, while recommending JSON-LD.
| Microdata | JSON-LD | |
|---|---|---|
| Location | Attributes across the markup | One script block |
| Coupling to design | Tight: layout changes move the data | None |
| Generated by | Templates, at each element | A serializer, in one place |
| Data and display drift | Impossible for visible values | Possible |
| Multiple vocabularies | Not idiomatic | Yes, via @context |
| Injectable via tag manager | No | Yes |
| Reviewability | Read the whole template | Read one object |
The recommendation is about operations. One function can produce a JSON-LD block, unit-tested against the page’s data model and reviewed as a single object. Microdata is spread across dozens of elements, so a component refactor or a translation pass can drop a property with no visible symptom.
Microdata is still the pragmatic choice in two situations. The first is an existing template that already emits correct Microdata: rewriting it as JSON-LD is churn with no ranking benefit and its own risk of new errors. The second is content where the data must provably match the visible text, such as prices, ratings, or event dates maintained by editors in a CMS. When the markup is the data, there is no second copy to fall out of date. See JSON-LD vs Microdata vs RDFa.
For developers
Parse Microdata with a library, not a selector sweep: extruct in Python, microdata-node in JavaScript, and Apache Any23 in Java implement the WHATWG algorithm, including the itemref and value-from-element rules hand-rolled parsers miss. Any23 and extruct also report RDFa and JSON-LD from the same fetch, the fastest way to find that a page emits two conflicting copies of one entity.
Because there is no browser DOM API, do not plan to read Microdata client-side. If application code needs the same data, keep it in the data layer and render both from one source. Put the itemprop attributes inside the components that render the values, and add a build-time test that extracts triples from a rendered page and asserts the expected types and properties.
For SEOs
Microdata is a supported structured data format with no ranking disadvantage. On a site that already emits valid Microdata, leave it. On new work, write JSON-LD, because it is faster to deploy, easier to audit, and the format every example in Google’s documentation uses.
The rule that matters more than format choice: do not declare the same entity twice in two syntaxes. A Product in Microdata and a Product in JSON-LD with different prices or names gives search engines two conflicting statements about one subject, and publishers can’t control which one wins. Audit with the Rich Results Test and validator.schema.org, against a rendered production page rather than a template sample. See structured data testing tools and entity SEO.
Common mistakes
itemprop outside an itemscope. A property with no enclosing item has no subject and produces no triple. This happens most often when a component carrying itemprop is reused outside the block that declared the item.
A wrong itemtype URL. itemtype must be an absolute URL. itemtype="Product", itemtype="schema.org/Product", and a misspelled type all yield an item with no recognized type. Parsers still accept http://schema.org/Product, but new markup should use https.
Duplicating an entity JSON-LD already declares. A CMS theme emitting Microdata plus an SEO plugin emitting JSON-LD is the usual cause. Pick one per entity.
Formatted numbers as text. <span itemprop="price">$1,200</span> yields the literal $1,200. Use content with a bare decimal and put the currency in priceCurrency.
Wrapping too much. An itemprop on a container that also holds a byline, share buttons, or navigation sweeps that text into the value.
Marking up content that is not on the page. Hidden meta values for facts stated nowhere in the visible content fall outside Google’s guidelines.
Related pages
- JSON-LD vs Microdata vs RDFa
- JSON-LD
- RDFa
- schema.org
- Structured data
- RDF triples: subject, predicate, object
FAQ
What is Microdata in HTML?
Microdata is an HTML syntax, defined in the WHATWG HTML living standard, that attaches structured data to visible page elements using the attributes itemscope, itemtype, itemprop, itemid, and itemref. The itemtype URL supplies the vocabulary, usually schema.org, and each itemprop becomes a property of the nearest enclosing item.
What do itemscope, itemtype, and itemprop do?
itemscope declares that an element describes one thing. itemtype gives that thing’s type as an absolute URL, such as https://schema.org/Product, and sets the vocabulary for its properties. itemprop names a property of the nearest enclosing item, taking its value from the element’s text, or from href, src, datetime, or content depending on the element.
Is Microdata still supported by Google?
Yes. Google Search Central lists Microdata alongside JSON-LD and RDFa as supported structured data formats, and it generates rich results from Microdata markup. Google recommends JSON-LD for new implementations because a single script block is easier to generate and validate, but Microdata is neither deprecated nor penalized.
Should I use Microdata or JSON-LD?
Use JSON-LD for new markup: one script block is easier to generate, test, and review than attributes spread through a template. Keep Microdata where it already works, or where the data must provably match the visible text, since Microdata values are the displayed values and cannot drift out of sync with them.
Sources and further reading
- WHATWG HTML Standard, Microdata section: https://html.spec.whatwg.org/multipage/microdata.html
- HTML Microdata (W3C Working Group Note): https://www.w3.org/TR/microdata/
- Google Search Central, “Introduction to structured data markup”: https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data
- schema.org: https://schema.org/
- Schema Markup Validator: https://validator.schema.org/
- extruct (structured data extraction library): https://github.com/scrapinghub/extruct
