JSON-LD Schema Markup: Types, Syntax, and Validation

Structured data is the translation layer between your content and the machines that consume it. When a search crawler or LLM reads your page, it processes HTML — a format optimized for visual rendering, not semantic understanding. JSON-LD inserts a parallel representation: a machine-readable JSON document, embedded in a <script> tag, that explicitly declares what your content is, who created it, and how it relates to the broader web of knowledge.

Google's official position is unambiguous: JSON-LD is the preferred and recommended format. Not Microdata, not RDFa — JSON-LD. The reasons are architectural. Unlike Microdata or RDFa, which interleave semantic annotations directly into your HTML attributes, JSON-LD lives in a <script type="application/ld+json"> block that is entirely separate from your visible content. This separation means you can update, add, or remove structured data without touching your UI code. It also means you can serve different structured data to bots without altering what users see, and that your markup will never accidentally affect your page's visual rendering.

Why Structured Data Drives AI Citation

The connection between schema markup and AI citation rates is not coincidental — it reflects how large language models and retrieval-augmented generation systems parse web content. When an LLM-backed system fetches a page to determine whether it is a credible source worth citing, it is performing rapid entity extraction under time constraints. Unstructured prose requires the model to infer entity types, relationships, and provenance from context. Structured data provides those answers directly.

The numbers reflect this mechanism. Pages cited in Google AI Overviews are 3.1× more likely to include schema markup compared to uncited pages. Among pages actually cited in AI Mode responses, 65% include structured data; for ChatGPT citations that figure rises to 71%. Schema markup has been shown to increase LLM content parsing accuracy by 40–60% by reducing ambiguity in entity type and relationship extraction.

The downstream business impact is measurable. Brands cited in AI Overviews earn 35% more organic clicks than non-cited competitors, and rich results — the structured snippets that schema enables in traditional SERPs — earn 35% higher CTR than standard listings. Structured data is simultaneously a ranking-quality signal, a rich-result eligibility requirement, and an AI-citation amplifier.

The JSON-LD Block: Placement and Syntax

JSON-LD belongs in the <head> element of your HTML. Although Google's documentation technically permits it in the <body>, placing it in <head> ensures it is available during the initial parse and avoids edge cases with lazy-loaded body content.

The basic wrapper looks like this:

<script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "Article",
    "headline": "Your Article Title"
  }
</script>

Three fields are universal to every JSON-LD block:

  • @context declares the vocabulary namespace — always "https://schema.org" for schema.org types.
  • @type identifies the entity type from the schema.org hierarchy.
  • All other properties are defined by the schema.org specification for that type.

To embed multiple schema types on a single page, use an array:

<script type="application/ld+json">
  [
    {
      "@context": "https://schema.org",
      "@type": "WebPage",
      "name": "How to Configure Redis Caching",
      "breadcrumb": { "@id": "#breadcrumb" }
    },
    {
      "@context": "https://schema.org",
      "@type": "BreadcrumbList",
      "@id": "#breadcrumb",
      "itemListElement": [
        { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://example.com/" },
        {
          "@type": "ListItem",
          "position": 2,
          "name": "Guides",
          "item": "https://example.com/guides/"
        },
        {
          "@type": "ListItem",
          "position": 3,
          "name": "Redis Caching",
          "item": "https://example.com/guides/redis-caching/"
        }
      ]
    }
  ]
</script>

The @id field creates an internal reference system — note how breadcrumb in the WebPage entity links to the #breadcrumb identifier on the BreadcrumbList. This is how you express relationships between entities on the same page without duplicating data.

High-Priority Schema Types

The following types cover the vast majority of use cases for developer-facing sites and content platforms. For each type, the properties listed represent the minimum set for rich result eligibility; omitting required properties does not degrade gracefully — it suppresses the rich result entirely.

Organization (homepage)

Place on your homepage. Establishes your brand entity and links it to external knowledge sources via sameAs.

{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "Acme Dev Tools",
  "url": "https://acmedevtools.io",
  "logo": {
    "@type": "ImageObject",
    "url": "https://acmedevtools.io/logo.png",
    "width": 280,
    "height": 60
  },
  "foundingDate": "2019",
  "description": "Open-source developer tooling for CI/CD pipeline automation.",
  "contactPoint": {
    "@type": "ContactPoint",
    "contactType": "customer support",
    "email": "[email protected]",
    "availableLanguage": "English"
  },
  "sameAs": [
    "https://github.com/acmedevtools",
    "https://twitter.com/acmedevtools",
    "https://www.linkedin.com/company/acmedevtools",
    "https://en.wikipedia.org/wiki/Acme_Dev_Tools",
    "https://www.wikidata.org/wiki/Q12345678"
  ]
}

The sameAs array is where entity recognition happens. Each URL tells Google "this Organization entity is the same thing as the entity at this external URL." Wikipedia and Wikidata links carry the most weight; GitHub and LinkedIn links contribute supporting corroboration.

WebSite (homepage)

Include alongside Organization on your homepage. The SearchAction property enables Google to display a sitelinks search box in your Knowledge Panel.

{
  "@context": "https://schema.org",
  "@type": "WebSite",
  "name": "Acme Dev Tools",
  "url": "https://acmedevtools.io",
  "potentialAction": {
    "@type": "SearchAction",
    "target": {
      "@type": "EntryPoint",
      "urlTemplate": "https://acmedevtools.io/search?q={search_term_string}"
    },
    "query-input": "required name=search_term_string"
  }
}

BreadcrumbList (all content pages)

BreadcrumbList improves SERP appearance by replacing the raw URL with a navigational path, and provides entity context — the crawler can infer that a page at position 3 in a breadcrumb chain is a child concept of the entity at position 2.

{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "name": "Home",
      "item": "https://acmedevtools.io/"
    },
    {
      "@type": "ListItem",
      "position": 2,
      "name": "Blog",
      "item": "https://acmedevtools.io/blog/"
    },
    {
      "@type": "ListItem",
      "position": 3,
      "name": "Understanding GitHub Actions Caching",
      "item": "https://acmedevtools.io/blog/github-actions-caching/"
    }
  ]
}

Article / BlogPosting (blog posts)

The dateModified field is critical for AI citation systems — freshness scoring is one of the primary filters AI Overviews applies when deciding which sources to cite. Omit it and you lose a significant freshness signal. Always keep it accurate.

{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": "GitHub Actions Caching: A Complete 2026 Guide",
  "description": "How to configure multi-layer caching in GitHub Actions to cut CI run times by up to 70%.",
  "datePublished": "2026-01-15T08:00:00Z",
  "dateModified": "2026-03-28T14:30:00Z",
  "image": {
    "@type": "ImageObject",
    "url": "https://acmedevtools.io/blog/github-actions-caching/hero.png",
    "width": 1200,
    "height": 630
  },
  "author": {
    "@type": "Person",
    "name": "Maya Patel",
    "url": "https://acmedevtools.io/authors/maya-patel/",
    "sameAs": ["https://www.linkedin.com/in/mayapatel-dev", "https://github.com/mayapatel"]
  },
  "publisher": {
    "@type": "Organization",
    "name": "Acme Dev Tools",
    "logo": {
      "@type": "ImageObject",
      "url": "https://acmedevtools.io/logo.png"
    }
  },
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "https://acmedevtools.io/blog/github-actions-caching/"
  }
}

Product (e-commerce and SaaS)

Product schema unlocks price, availability, and review rich results. The offers property is required; without it Google cannot render the pricing rich result.

{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Acme CI Analyzer Pro",
  "description": "Real-time CI/CD pipeline performance analytics with bottleneck detection.",
  "image": "https://acmedevtools.io/products/ci-analyzer-pro.png",
  "brand": {
    "@type": "Brand",
    "name": "Acme Dev Tools"
  },
  "offers": {
    "@type": "Offer",
    "price": "49.00",
    "priceCurrency": "USD",
    "priceValidUntil": "2027-01-01",
    "availability": "https://schema.org/InStock",
    "url": "https://acmedevtools.io/products/ci-analyzer-pro/"
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.8",
    "reviewCount": "312"
  }
}

FAQPage

FAQPage markup can render up to three Q&A pairs as expandable rich results directly in the SERP. Note: Google has restricted this to government and health domains for some query categories. Test with the Rich Results Test to confirm eligibility for your site category.

{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "What is the GitHub Actions cache size limit?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "GitHub Actions provides 10 GB of cache storage per repository. Caches older than 7 days or least-recently-used entries are evicted when the limit is reached. You can use the actions/cache step with a composite key to maximize cache reuse across branches."
      }
    },
    {
      "@type": "Question",
      "name": "Can I share caches between GitHub Actions workflows?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Yes. Caches are scoped to the current branch and can fall back to the default branch. A workflow on a feature branch will first attempt to restore a cache with an exact key match, then fall back to matching partial keys on the same branch, and finally fall back to the default branch cache."
      }
    },
    {
      "@type": "Question",
      "name": "Does GitHub Actions caching work with Docker builds?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Yes, via docker/build-push-action with cache-from and cache-to parameters pointing to GitHub's cache backend (type=gha). This preserves Docker layer cache between workflow runs and can cut image build times by 40–80% for layers that do not change frequently."
      }
    }
  ]
}

Validation: Catching Silent Failures

A schema markup error does not produce a visible page error — it simply silently prevents rich results from appearing. Google provides two official validators:

Google Rich Results Test (search.google.com/test/rich-results): Enter a URL or paste HTML. It shows which rich result types are eligible, which are blocked, and the specific missing or invalid properties causing suppression. Use this as your primary validation tool before deploying any structured data changes.

Schema.org Validator (validator.schema.org): Validates against the full schema.org specification, including properties and types that Google does not use for rich results. Useful for catching type mismatches and undefined properties that the Rich Results Test may not flag.

The most common silent failures are:

  • Missing required properties: Every schema type has a set of required properties. For Article, headline, image, and datePublished are required. Any one of these missing means zero rich result eligibility.
  • Incorrect @type nesting: Using "author": "Maya Patel" (a string) instead of "author": { "@type": "Person", "name": "Maya Patel" } (an object) strips the entity relationship, turning a Person entity into an anonymous string.
  • Invalid date formats: datePublished and dateModified must be ISO 8601 format (2026-03-28T14:30:00Z). Human-readable strings like "March 28, 2026" are not valid.
  • Image dimensions too small: Google requires Article images to be at least 1200px wide at a 16:9 ratio for maximum rich result eligibility. Thumbnails will not qualify.

Run the Rich Results Test after every structured data deployment. Treat failed validation the same way you would a failing unit test — it represents a measurable business regression.