Skip to main content

Structured Data with JSON-LD: A Developer's Implementation Guide

Updated 6 min readMarkdown

Structured data is one of the few SEO tasks that looks exactly like normal software work: a schema, a data source, a template, and a validator. Done well, it gives search engines an unambiguous description of what a page is about and can make the page eligible for enhanced search results. Done carelessly, it produces invalid markup, mismatches with visible content, and occasionally manual actions.

This guide covers how to generate JSON-LD from your existing data, which types are worth implementing, and how to test it in CI.

Why JSON-LD

Structured data can be expressed as Microdata, RDFa or JSON-LD. Google supports all three but recommends JSON-LD, and for developers it is the obvious choice: it lives in a single <script type="application/ld+json"> block, it does not tangle with your HTML templates, and it can be built from the same data objects that render the page.

The vocabulary comes from Schema.org. When people say schema markup, they mean Schema.org types and properties, regardless of syntax.

What structured data can and cannot do

Structured data can make a page eligible for rich results like product price and availability, review snippets, breadcrumbs, and event details. It also helps search engines connect your pages to real-world entities: your organization, products, people and places.

It does not guarantee rich results, and it is not a direct ranking factor in the "add schema, rank higher" sense. Google decides whether to show enhancements based on eligibility, quality and the query.

Some features have also narrowed over time. Since 2023, Google shows FAQ rich results mainly for well-known government and health sites, and HowTo rich results were removed. FAQPage markup is still valid Schema.org and other consumers may read it, but do not promise a client FAQ snippets in Google.

Types worth implementing first

Page type Schema type(s) Typical benefit
Home / about Organization, WebSite Entity clarity, logo, sameAs links
Product Product, Offer, AggregateRating Price, availability, ratings in results
Article / blog Article / BlogPosting Author, dates, image
Any nested page BreadcrumbList Breadcrumb trail in results
Local business LocalBusiness subtype Address, hours, geo
Software SoftwareApplication Ratings, price, OS

Organization

{
  "@context": "https://schema.org",
  "@type": "Organization",
  "@id": "https://example.com/#org",
  "name": "Example Co",
  "url": "https://example.com/",
  "logo": "https://example.com/logo-512.png",
  "sameAs": [
    "https://www.linkedin.com/company/example",
    "https://github.com/example"
  ]
}

The @id lets other blocks reference this organization instead of repeating it. That is how you build a connected graph rather than isolated islands of markup. Consistent organization data, combined with mentions elsewhere on the web, is one of the inputs that can contribute to a knowledge panel, though there is no markup that triggers one directly.

Product

Product schema should be generated from the same record that renders the price on screen:

function productJsonLd(p) {
  return {
    '@context': 'https://schema.org',
    '@type': 'Product',
    name: p.title,
    sku: p.sku,
    image: p.images.map(i => i.url),
    description: p.summary,
    brand: { '@type': 'Brand', name: p.brand },
    offers: {
      '@type': 'Offer',
      price: p.price.toFixed(2),
      priceCurrency: p.currency,
      availability: p.inStock
        ? 'https://schema.org/InStock'
        : 'https://schema.org/OutOfStock',
      url: p.canonicalUrl,
    },
  };
}

Generating from one source of truth avoids the most common problem we find: markup that says $49 while the page says $59 because someone edited one and not the other.

Breadcrumbs help users and give search engines a clear hierarchy. Build the JSON-LD from the same route data that renders the visible trail:

{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    { "@type": "ListItem", "position": 1, "name": "Docs", "item": "https://example.com/docs/" },
    { "@type": "ListItem", "position": 2, "name": "API", "item": "https://example.com/docs/api/" },
    { "@type": "ListItem", "position": 3, "name": "Auth" }
  ]
}

Rendering JSON-LD in modern frameworks

Server-render the script tag. Google can read JSON-LD injected by JavaScript after rendering, but other consumers often cannot, and you lose nothing by sending it in the initial HTML.

export default function ProductPage({ product }) {
  return (
    <>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(productJsonLd(product)) }}
      />
      {/* page content */}
    </>
  );
}

One security note: if any field can contain user input, escape < as < in the serialized JSON so a stray </script> cannot break out of the tag.

Rules that keep you out of trouble

  1. Mark up what is visible. Structured data must describe content users can see on the page. Hidden reviews or invented ratings violate Google's guidelines.
  2. One primary type per page. Supporting types (breadcrumbs, organization) are fine; a product page that also claims to be a recipe is not.
  3. Use absolute URLs and the canonical version of each.
  4. Keep it current. Out-of-stock products marked InStock, or old event dates, erode trust.
  5. Do not mark up self-serving reviews of your own business on your own site for review snippets.

Testing and monitoring

  • Rich Results Test shows which Google features a page is eligible for.
  • Schema Markup Validator (validator.schema.org) checks general Schema.org validity.
  • Search Console enhancement reports show errors and warnings across the site over time.
  • CI checks: parse the JSON-LD from built pages and validate required properties with a JSON Schema or a small test suite, so a template change cannot silently strip offers.

An example from client work

For a B2B solar design services firm that had seen a year-long click decline, schema was one part of a broader programme that also covered content, internal linking and on-page fixes. The B2B website search growth case study describes how those changes coincided with a return to growth. We are careful not to credit schema alone; it works best as part of a coherent technical foundation.

FAQ

Is JSON-LD better than Microdata for SEO? Search engines treat valid markup equivalently. JSON-LD is simply easier to maintain and less error-prone.

Can I put JSON-LD in the body? Yes. Google reads it in the head or body.

Should every page have structured data? Most pages benefit from at least BreadcrumbList and an Organization or WebSite reference. Add specific types where they truly describe the content.

Why did my rich results disappear? Check for new errors, policy changes for that feature, and whether the visible content still matches the markup.

Wrapping up

Treat structured data as a typed API for search engines: generate it from your real data, render it on the server, validate it in CI, and only describe what users can see.

If you want help designing a schema graph for your site, get a free growth plan from Top SEO Experts.

Published by Top SEO Experts.

About the author

  • Top SEO Experts is a US SEO agency in Glastonbury, CT. We don't sell rankings - we build organic acquisition systems: technical SEO, content, programmatic and AI search, local SEO, web development and digital PR. https://topseoexperts.us

No comments yet. Be the first to comment.

More from this blog