Schema.org structured data: implementing it
Priority types (Organization, Product, FAQPage, Article, BreadcrumbList), an annotated JSON-LD example, and validation tools.
Once the principle of structured data is understood, the practical question remains: which Schema.org types to implement first, how to write the corresponding JSON-LD, and how to verify the markup is valid.
Priority types
Five types cover the large majority of a site's needs:
Organization: the company's identity (name, logo, social profiles, contact details) — usually set once, on the homepage or globally.Product: a product page, with price, availability, and reviews.FAQPage: a list of questions and answers, particularly useful for being picked up directly in a generative AI's answer.Article: editorial content (blog, news, guide), with author, publication date, and update date.BreadcrumbList: the breadcrumb trail, making a page's position in the site's hierarchy explicit.
Other types exist for more specific needs: Event for an event with a date and location, LocalBusiness for a business with a physical address and hours, Review for an individual review distinct from an aggregate rating, or HowTo for content structured as steps. It's better to correctly implement the five priority types before extending markup to more specialized types whose benefit depends heavily on the industry.
Annotated JSON-LD example
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Product name",
"description": "Short, factual product description.",
"brand": {
"@type": "Brand",
"name": "BrandName"
},
"offers": {
"@type": "Offer",
"price": "99.00",
"priceCurrency": "EUR",
"availability": "https://schema.org/InStock"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.6",
"reviewCount": "128"
}
}
</script>
Every property should reflect information actually present and verifiable on the page: the displayed price must match the marked-up price, and the average rating must correspond to real, viewable reviews.
For a frequently-asked-questions page:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "How long does setup take?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Setup generally takes between 2 and 5 business days depending on project complexity."
}
}
]
}
</script>
Where to place the code
JSON-LD is usually inserted in the <head> or just before the closing </body>, with no dependency on the page's visual layout — unlike semantic HTML5 markup, which stays closely tied to the document's visual structure. This is one of JSON-LD's advantages over alternative syntaxes (microdata, RDFa) that require annotating the visible HTML tags directly. This independence from visual rendering also makes it possible to generate it dynamically from a database (a product catalog, a content management system) without manual work on each page, making it particularly well suited to sites with a large number of similar pages.
Validation tools
Before publishing, two checks are essential: syntax validation (is the JSON well-formed, with no stray comma or missing quote) and semantic validation (do the types and properties used actually exist in the Schema.org vocabulary, and are they consistent with each other). Google's rich results testing tools and community Schema.org validators help catch both categories of errors before going live, and confirm that no required property is missing for the type in use.
This check deserves repeating after every change to the template that generates the markup, not just at initial implementation: a CMS update, a database structure change, or a theme update can silently break a dynamically generated JSON-LD block, with nothing visually flagging it on the page.
Combining several types on one page
A page can legitimately carry several Schema.org blocks at once: a product page might combine Product for the listing itself, BreadcrumbList for the breadcrumb trail, and Organization for the identity of the brand selling it. These blocks can be declared separately in several <script> tags, or grouped into a single block via the @graph property, which lets you explicitly link several entities together within one JSON-LD document. This second approach becomes preferable as soon as entities need to reference each other (an article's author, a product's brand), since it avoids duplicating information across several independent blocks.
Common mistakes
- Duplicated or contradictory markup across several JSON-LD blocks on the same page.
- Marked-up data that no longer matches the visible content after an update (price changed on the page but not in the JSON-LD).
- Using a Schema.org type that doesn't actually match the content (marking a blog page as
Product). - Malformed JSON that silently invalidates the entire block.
- Multiplying secondary types before correctly implementing and validating the priority types.
This lesson closes the technical markup portion of the module. The complete technical checklist that follows rounds up every point covered so far into an actionable list, before moving on to the fundamentals of GEO itself.