DEV Community

Structured Data That Machines Read

Structured data is the one place where you tell a machine what your page means rather than hoping it infers it. It is also where honest sites quietly stop being honest, and where a mechanical detail - that JSON-LD lives inside a element - decides whether half the systems you care about ever see it. Three encodings, one vocabulary schema.org is a vocabulary of types and properties. It can be expressed three ways in a page, and the choice matters more than it looks. | Encoding | Description | |---|---| | JSON-LD | A JSON object in a element. Separate from the visible markup, so it survives a redesign. The recommended form, and the one with the mechanical caveat in the next section. Microdata itemscope, itemtype and itemprop attributes on the visible elements themselves. Cannot drift from what is displayed, because it is attached to it. Verbose, and painful to keep correct across a component library. RDFa The same idea with a different attribute set, from the wider linked-data world. Fully supported by the major parsers and rarely chosen for new work. Use JSON-LD unless you have a specific reason not to. It is generated from the same variables your template already has, which is the only arrangement in which the markup and the page cannot disagree. Why JSON-LD is invisible to a text extractor Here is the mechanism nobody writes down, and it is tier-2 observable in one command. A structured-data parser looks for script elements of type application/ld+json and reads their contents. An HTML-to-text converter - the kind that sits in the fetch stage of a retrieval pipeline, turning a fetched page into something to chunk - does the opposite: it strips script and style elements first, precisely because their contents are not prose and would poison the text with JavaScript. Your JSON-LD is discarded before the text is ever chunked. Prove it on your own page in one line, with any HTML-to-text tool: # Does the structured data survive text extraction? curl -sS https://example.com/some-page > page.html # What a structured-data parser sees: grep -c 'application/ld+json' page.html # What a text extractor sees (python-readability, trafilatura, # lynx -dump, or your own stripper) - search the output for a value # that appears ONLY in the JSON-LD: lynx -dump -nolist page.html | grep -c 'a-value-only-in-your-jsonld' If the second count is zero, the conclusion is not that structured data is useless. It is that structured data reaches parsers, and visible text reaches extractors, and you should not rely on one to carry a fact the other needs. Every fact that matters must be in the prose. The markup is a second, machine-typed statement of facts the page already makes. Microdata behaves differently here, because its values are the visible text - an extractor keeps them by definition. That is not a reason to switch, but it is the reason the rule below is not merely an ethical preference. The rule that keeps markup honest One rule, and it makes several other decisions for you: nothing in the structured data may be a fact the page does not also show a human. Every value passed to the generator should be the same variable the visible markup renders. What that rules out, concretely: An aggregateRating with no reviews on the page. The most abused property in the vocabulary and the one most likely to earn a manual action. A priceValidUntil you have not committed to. If you cannot honour the date, it is not a fact. FAQ markup for questions not on the page. The guidance is explicit that the question and answer text must both be visible. An author nobody wrote. If the page has no byline, the author is the organisation, and saying so is more credible than inventing a person. An image that does not illustrate the article. Pointing a thousand articles at one site-wide mark is a claim that each illustrates itself; omitting the property is more honest and costs nothing. The rule also gives you an implementation test: if your generator takes an argument that is not already on the page, that argument is the bug. The types worth the effort These types and properties all exist in the vocabulary and are widely consumed. Pick by what your page is, not by what sounds impressive. Type Description Article / TechArticle / BlogPosting For prose. TechArticle is an Article subtype and is the accurate choice for documentation and technical explainers. Carries headline, description, datePublished, dateModified, author, publisher, inLanguage, timeRequired. BreadcrumbList The trail you already render, as ListItem entries with position and item. Cheap, unambiguous, and it tells a parser your site's shape without it inferring one from your navigation. Organization Your identity, on one page, with sameAs pointing at the profiles that are also you. This is the property that ties your identifiers together and it matters for entity resolution - see the page on false claims about your company. WebSite Site-level name and URL, usually with the Article's isPartOf pointing at it. CollectionPage + ItemList For a hub that lists other pages. The ItemList should be the same list in the same order the page renders, which is the point of it. Product / Offer For something purchasable, with price and priceCurrency. Only where the price is on the page and current. SoftwareApplication For a tool or an app: applicationCategory, operatingSystem, and a zero-price Offer where it is genuinely free. Do not describe a calculator as an Article. Dataset For downloadable data, with distribution, license and creator. Under-used, and it is the type most likely to make a data page findable by something that wants data. FAQPage / QAPage Question and Answer entries. Still valid vocabulary and still parsed, but see the section on rich results before assuming it earns a display change. citation / isBasedOn / license Properties rather than types, and the most underused ones here. They state what a page rests on and what may be done with it, in machine-readable form. A complete article block Generated from the page’s own fields, with no value invented. The escaping detail in the last line is not optional: a string in your data containing a closing script tag would end the element early, which is the one genuine injection risk in a block like this. function articleJsonLd ( page , siteUrl ) { const url = ${ siteUrl } /learn/ ${ page . slug } ; return { " @context " : " https://schema.org " , " @type " : " TechArticle " , " @id " : url , mainEntityOfPage : { " @type " : " WebPage " , " @id " : url }, headline : page . title , // the visible description : page . summary , // the meta description datePublished : page . published , // the date the URL began to exist dateModified : page . updated , // the visible "updated" line timeRequired : PT ${ page . minutes } M , // the visible "N min read" inLanguage : " en " , author : { " @type " : " Organization " , name : " Example " , url : siteUrl }, publisher : { " @type " : " Organization " , name : " Example " , url : siteUrl }, }; } // Rendering it. The escape matters. script type = " application/ld+json " dangerouslySetInnerHTML = {{ __html : JSON . stringify ( data ). replace ( / , " \ u003c " ), }} / > timeRequired takes an ISO 8601 duration, so β€œ6 min read” is PT6M . datePublished and dateModified take ISO dates or datetimes. Getting the format wrong is the most common validator error and it is silent otherwise. What stopped producing rich results Two changes from 2023 are still being sold as tactics and are worth knowing precisely, because they are tier-1 facts you can read in the operator’s own documentation. FAQ rich results were restricted. Google announced in August 2023 that the FAQ rich result would generally be shown only for well-known authoritative government and health sites. The markup is still valid and still parsed; the display change is what went away for everyone else. HowTo rich results were removed. Announced in the same change, limited and then dropped as a search feature. The lesson generalises past those two: a display feature is a product decision and can be withdrawn, while the vocabulary is a standard and does not disappear. Mark up your page because the markup is a true, structured statement of what the page contains. If you are marking it up for a specific visual treatment, you have bought an asset with an unannounced expiry date. Validating it, and testing extraction Validate the vocabulary. The Schema Markup Validator at validator.schema.org checks your JSON against schema.org itself, with no opinion about any search product. This is the one that tells you whether your types and properties are real. Check the search-product view. Google’s Rich Results Test tells you whether a specific feature is eligible, which is a narrower and more volatile question. Validate the rendered page, not the source. If your markup is injected client-side, paste the URL rather than the source - or better, move the block to the server response, because a non-rendering fetcher will never run the injection at all. See JavaScript rendering and what crawlers see . Diff the markup against the page. Take every value in the JSON and confirm the string appears in the visible text. A twenty-line script that does this in CI is the cheapest possible defence against the whole class of dishonest-markup problems. Run the extraction test from the second section, so you know which of your facts survive to the text a chunker sees. What structured data does not do It is not a ranking factor in the sense people mean, and no assistant operator documents using it to choose sources. Claims that adding JSON-LD raises your citation rate are tier 3 under the scale in what is real and what is sold - unverifiable at your scale and unsupported by any public documentation. What it does do is cheap, real and independent of that question: it removes ambiguity for parsers that read it, it makes your dates, authorship and identity machine-readable, and it forces you to write d

Read on DEV Community ↗ ← Back to News

Comments

No comments yet. Start the discussion.