Skip to content

How structured data validation works

Three hands-on demos, each running this site's real validation engine. Use them to understand why a checker says what it says, not just what to change.

What a validator does, in five passes

Step through the passes. Each one can only catch the mistakes that survive the one before it.

1. Find

Locate every <script type="application/ld+json"> in the HTML. Markup injected later by JavaScript only exists in the rendered page.

Catches: No markup at all; markup only in the rendered DOM; wrong script type.

Order matters

Each pass only sees what survived the one before. That's why fixing a syntax error can suddenly reveal ten new warnings: they were always there, but the parser never got far enough to find them. Work top-down, parse first, then vocabulary, then feature rules.

A validator can only report what the markup actually says, not what the author meant. Look before you explain is a good rule for the sky too; ahaboo has a narrated explainer on why the Moon has phases.

Required vs recommended: flip the properties

This runs the same engine as the validator. Switch properties on and see which rule fires.

Properties
errorProduct snippet: not eligibleMerchant listing: not eligible
  • error Product snippet needs one of: offers, review, aggregateRating
  • warning Product snippet: 7 recommended properties missing
  • warning Merchant listing: 1 recommended property missing
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Trailhead 28L Daypack"
}

Required, recommended, and everything else

Google's docs split properties into required (the item isn't eligible without them) and recommended (optional, but more complete data gives Google more to show). Everything else is valid schema.org that Google may simply not use. A Product with only a name is valid schema.org and still not eligible for a product snippet: it needs one of offers, review or aggregateRating.

Nested objects vs @graph: same facts, three spellings

Pick a version. The diagram is what the validator resolves, not a drawing.

{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "Repair, don't replace",
  "author": {
    "@type": "Person",
    "name": "Mara Lindqvist"
  },
  "publisher": {
    "@type": "Organization",
    "name": "Northfold",
    "url": "https://example.com"
  }
}
ArticlePersonOrganizationauthorpublisher

The publisher object sits inside the article. Simple, but if three pages mention Northfold you repeat it three times, and each copy can drift.

References are string matches

An @id is just an identifier, usually a URL with a fragment such as https://example.com/#org. A reference works only if the string matches exactly; #org and #organisation are unrelated nodes. Validators that resolve references, like this one, will warn when a pointer leads nowhere.

Ready to try it on your own markup? Open the schema markup validator.

Questions

Why does one comma break the whole block?

JSON parsers are strict by design: they stop at the first character that doesn't fit the grammar. There is no partial result to fall back on, so the block is discarded.

Do I have to use @graph?

No. Nested objects and @graph with @id references produce the same data. @graph helps when several entities on a page share an organisation, author or website.

Why are property names case-sensitive?

They expand to URLs such as https://schema.org/brand. "Brand" expands to https://schema.org/Brand, which is a type, not a property, so it doesn't mean what you intended.