Structured data (JSON-LD)

We covered schema at a strategic level in on-page. Here's the technical implementation: where to put it, how to generate it dynamically, how to validate, how to avoid penalties.

JSON-LD placement

JSON-LD goes in the <head> in a <script type="application/ld+json"> tag. Can also go in <body>, but head is convention.

Nesting vs multiple scripts

You can have multiple JSON-LD blocks on one page OR nest multiple types inside one block via @graph:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "WebSite",
      "@id": "https://example.com/#website",
      "url": "https://example.com/",
      "name": "Example Site"
    },
    {
      "@type": "Article",
      "headline": "...",
      "isPartOf": { "@id": "https://example.com/#website" }
    }
  ]
}
</script>

@graph is cleaner for complex pages. IDs let entities reference each other.

Dynamic generation

For CMS-generated content, produce JSON-LD dynamically from content metadata. Most modern CMS plugins (Yoast, RankMath, Schema Pro) handle this. For custom builds:

Avoid client-side schema generation. Googlebot may not always render JS-injected schema.

Essential schema types

Organization (homepage + about)

{
  "@type": "Organization",
  "name": "Your Company",
  "url": "https://yourcompany.com",
  "logo": "https://yourcompany.com/logo.png",
  "sameAs": [
    "https://twitter.com/yourcompany",
    "https://linkedin.com/company/yourcompany"
  ]
}

Article (blog posts)

{
  "@type": "Article",
  "headline": "...",
  "author": { "@type": "Person", "name": "Samuel Ochoa" },
  "datePublished": "2026-04-18",
  "dateModified": "2026-04-18",
  "image": "https://example.com/hero.jpg",
  "publisher": { "@type": "Organization", "name": "Example" }
}

Product (e-commerce)

{
  "@type": "Product",
  "name": "Product Name",
  "image": "...",
  "description": "...",
  "offers": {
    "@type": "Offer",
    "priceCurrency": "USD",
    "price": "99.00",
    "availability": "https://schema.org/InStock"
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.5",
    "reviewCount": "127"
  }
}

FAQPage (Q&A sections)

{
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "What is...?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "..."
      }
    }
  ]
}

Note: Google has restricted FAQ rich results heavily since 2023. Still fine to implement, just don't expect the rich result everywhere.

BreadcrumbList

{
  "@type": "BreadcrumbList",
  "itemListElement": [
    { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://example.com" },
    { "@type": "ListItem", "position": 2, "name": "Blog", "item": "https://example.com/blog" },
    { "@type": "ListItem", "position": 3, "name": "Post", "item": "https://example.com/blog/post" }
  ]
}

Validation + debugging

Common mistakes

Performance note

Schema in JSON-LD adds HTML weight. Not usually significant, but for very large sites with many entities per page (thousands of products on a category page), be mindful. Consider serving minimal schema on listing pages and full schema on detail pages.