Structured data basics: JSON-LD for small sites

What structured data is, why JSON-LD is the usual format, two small examples, where the code goes, and how to avoid duplicates and extra page weight.

BeginnerHow-to6 min readUpdated October 30, 2026

In this guide
  1. What it is
  2. Three formats, one choice
  3. Two small examples
  4. The types you will meet
  5. Where it goes
  6. Rules that keep it honest
  7. In WordPress and other builders
  8. The speed side
  9. How to check
  10. Mistakes to avoid
  11. Check your own page
  12. Sources

What it is

Schema.org describes itself as a joint effort between search engines to improve the web with a markup vocabulary. Its FAQ says on-page markup helps search engines understand the information on web pages and provide richer search results. The vocabulary is a set of types, such as Organization, LocalBusiness and Article, and properties, such as name, url and address. Schema.org is not a formal standards body.

The 2025 Web Almanac puts it plainly: structured data is not a direct ranking factor, but it helps search engines understand the context of a page and can power rich results. Half of the home pages in its data had some, 50% on both desktop and mobile.

Lighthouse's documentation says the same about purpose. You can tell search engines that your page is an article, a job posting or an FAQ, and marking content up makes it more likely to appear in rich results. Its structured data audit is manual, so it does not affect the Lighthouse SEO score.

Three formats, one choice

Schema.org's FAQ says the markup can be written in Microdata, RDFa or JSON-LD, and that some things are much harder in Microdata, such as mixing vocabularies. In the Almanac, JSON-LD was on 43% of home pages, by far the most common, and microdata was on about 19% of inner pages. The Almanac adds that Google typically recommends JSON-LD as the easiest form to implement and maintain. Pick it for new work. It sits in one block, apart from the visible HTML, which makes it easier to write, review and remove.

Two small examples

A company-wide block for the home page:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "Example Plumbing Co.",
  "url": "https://example.com/",
  "logo": "https://example.com/img/logo.png",
  "sameAs": [
    "https://www.facebook.com/exampleplumbing",
    "https://www.linkedin.com/company/exampleplumbing"
  ]
}
</script>

A business with a street address, for a contact or location page:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "LocalBusiness",
  "name": "Example Plumbing Co.",
  "url": "https://example.com/",
  "image": "https://example.com/img/storefront.jpg",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "100 Example Street",
    "addressLocality": "Miami",
    "addressRegion": "FL",
    "postalCode": "33101",
    "addressCountry": "US"
  },
  "openingHours": "Mo-Fr 08:00-17:00"
}
</script>

I checked that both blocks parse as JSON, and I checked each type and property against the schema.org vocabulary file. LocalBusiness is a subtype of Organization and Place, openingHours belongs to it, and sameAs and image belong to every Thing. The names and addresses are made up.

Schema.org's FAQ says both https://schema.org and http://schema.org are fine as the context, with https preferred in new examples.

The types you will meet

In the Almanac, WebSite was the most common type on home pages: 36% on mobile in 2025, against 35% in 2024 and 30% in 2022. Organization overtook WebPage for the first time in 2025. On inner pages the most common type was ListItem, at 27% on mobile, down from 30%. A ListItem is how a breadcrumb trail is written. Schema.org describes a BreadcrumbList as a chain of linked pages, typically described by their address and name and ending with the current page, with position numbers that begin at 1 for the top of the trail:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "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": "Image formats", "item": "https://example.com/guides/image-formats/" }
  ]
}
</script>

JSON-LD can also group several items under one @context with an @graph list, which the specification says saves repeating the context. Some tools write one block this way, and others write one block per item. Both are valid.

Where it goes

Rules that keep it honest

In WordPress and other builders

SEO plugins, themes and page builders often write JSON-LD, and more than one may be active. The result can be two Organization blocks that disagree, or a heavy page. See themes and plugins.

  1. View the page source and search for application/ld+json.
  2. Count the blocks. Open each and read its @type.
  3. If two write the same type, turn one off in its settings.
  4. Check the pages that matter most: the home page, a contact page and one deep page.

From a terminal, curl -s https://example.com/ | grep -c 'application/ld+json' counts the blocks on a page. This Node one-liner goes further. It lists the types in each block, reads @graph lists too, and says so when a block is not valid JSON:

curl -s https://example.com/ | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{for(const m of s.matchAll(/<script type="application\/ld\+json">([\s\S]*?)<\/script>/g)){try{const j=JSON.parse(m[1]);console.log(JSON.stringify([].concat(j["@graph"]||j).map(x=>x["@type"])))}catch(e){console.log("not valid JSON")}}})'

I tested it on a page with a grouped block, a breadcrumb block and a broken block. It printed ["WebSite","Organization",["WebPage","FAQPage"]], ["BreadcrumbList"] and not valid JSON.

The speed side

Structured data is part of the HTML, so every byte travels with every page. The two examples above are about 300 and 430 characters. A plugin that writes a large graph for a simple page is a different story, and the HTML it adds is not cached apart from the page. Because the block is data, it does not run and does not block rendering. Keep it short, keep one copy, and measure page weight if a plugin adds a lot. See page weight and requests.

How to check

  1. Read it yourself. One stray comma makes a JSON block unreadable, so use a validator that checks the syntax.
  2. Use a testing tool. Lighthouse's audit is manual, and its documentation points to a linter and to a search engine's testing tool instead. Tool names and addresses change, so look for a current one from schema.org or a search engine.
  3. Compare with the page. Does every fact in the markup appear on the page?
  4. Check after each plugin or theme update. Output changes silently.

Mistakes to avoid

Check your own page

Run the free audit, then view the source of your home page and one inner page. Count the application/ld+json blocks, read their @type values, and confirm that each fact in them is on the page.

Sources

Start here

Free website audit

Live Google data for any public page: mobile and desktop.

Mobile + desktop · Lighthouse lab test · Real-user Chrome data when Google has it

Rather have this done for you? Technical SEO · Book a call

Related guides

All guides →