Claims in machine-readable form

Structured data is a set of explicit assertions about a page, written in a vocabulary consumers agree on. The format almost everyone uses is JSON-LD: a block of JSON inside a <script type="application/ld+json"> element, in the head or the body. Because it lives apart from the markup, it can be read without rendering the page.

Each block is one JSON object whose @context points at schema.org and whose @type names the class. Properties whose value is itself a typed entity are written as nested objects, which is what lets a consumer tell a price from a phone number when both are bare strings.

What each type expects

@typeProperties writtenNotes
Organizationname, url, logo, description, sameAs[]Google's guidance asks for a logo of at least 112×112 pixels; sameAs takes profile URLs.
Personname, url, jobTitle, email, worksForUseful as an article's author, rarely worth a block alone.
Articleheadline, description, author, datePublished, dateModified, imageHeadline, image and publication date are load-bearing; Google's Article documentation caps the headline at 110 characters.
Productname, description, image, brand, offers with price, priceCurrency, availabilityThe offer is what makes the block useful.
LocalBusinessname, description, url, telephone, addressBelongs on the location page, not site-wide.
Eventname, description, startDate, image, locationName, start time and a location for anything physical are the minimum.
FAQPagemainEntity[] of Question with acceptedAnswerThe questions must appear on the page. Since August 2023 Google restricts FAQ rich results to a limited set of authoritative government and health sites.
BreadcrumbListitemListElement[] of ListItem with position, name, itemPositions are numbered from 1, without gaps.

A generated Product block

With a name, price and currency filled in and availability set to in stock, the payload is indented two spaces per level:

{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Northline Trail 7",
  "offers": {
    "@type": "Offer",
    "price": "129.00",
    "priceCurrency": "EUR",
    "availability": "https://schema.org/InStock"
  }
}

Two details are easy to miss: currency defaults to USD when the field is left untouched, and the JSON is only the payload, wrapped by the generator in the <script type="application/ld+json"> element.

Where this goes wrong

Common questions

Should the block go in the head or the body?

Both work when the element is static. Injecting it in the body is common, because a template can place it near the content it describes.

Can JavaScript insert the block?

Yes, and the page is read after a client-side render, but that makes the block depend on the renderer running. If visibility is the point, a static block cannot fail to appear.

How do I check it?

Run the URL and the emitted markup through Google's Rich Results Test and the Schema Markup Validator. The first reports eligibility for specific result features, the second reports vocabulary errors. Neither tells you the values are untrue.

Can one page carry several schema types?

Yes. A product page commonly carries a product block, a breadcrumb block and a site-wide organization block. Several elements are fine; contradictory values are the problem.