# JSON-LD: how to write it, where to put it, how to test it

You want machines to read your pages without guesswork. JSON-LD is the format Google recommends. This guide shows a working example, where to put it, and how to test it without wasting a sprint.

Updated 2026-09-14 · Source: https://porteur.ai/guides/json-ld

## Why JSON-LD is the default

Use JSON-LD for structured data on a product site. Google recommends it, and it keeps your HTML cleaner than in-line attributes.

JSON-LD is not a ranking factor. It makes your page eligible for rich results and helps machines understand your entities and facts.

You can add or change it without touching visible copy. That lowers the risk of layout regressions and speeds up reviews.

## JSON-LD vs microdata

| Question | JSON-LD | Microdata or RDFa |
| --- | --- | --- |
| Where it lives | A script block you can place once | Inline attributes on many tags |
| Ease of editing | One place to change | Many places to change |
| Google support | Recommended by Google as of 2026 | Read by Google, not recommended |
| Works with JS frameworks | Yes, as a script or injected string | Possible but brittle |
| Risk to layout | None, it is not rendered | Higher, attributes sit in HTML |

If you already ship microdata, do not duplicate it with JSON-LD on the same facts. Keep one source to avoid conflicts in the graph.

## Where to put JSON-LD: head or body

Place your JSON-LD in the head. It keeps the markup close to metadata and is easy for your team to find.

Body also works. Google reads JSON-LD in head or body. Both are valid as of 2026.

Server render the script where you can. Google renders pages, so injected JSON-LD is seen. Most answering AI crawlers do not run scripts yet, so do not rely on client injection for them.

Use one script per page or one @graph holding all your types. Both patterns are fine. A single @graph scales better on complex pages.

## One @graph for several types

Put several types in one @graph. Link them with @id so machines can join the dots.

- Use absolute URLs in @id and url fields. Do not use relative paths.
- Give each node a stable @id, for example your homepage with a hash: https://yourproduct.com/#organization.
- Reference nodes by @id instead of nesting deeply. This keeps the graph tidy.
- Only mark up content that exists on the page. If it is not visible, it risks a policy violation.

On a product homepage, your graph can include Organization and WebSite. On a product page, add Product, Offer and AggregateRating. On a blog post, add Article and BreadcrumbList.

## A complete example: Organization and WebSite

Drop this script on https://yourproduct.com. Adjust names, images and policies. The WebSite node omits SearchAction. Google removed the sitelinks search box in November 2024, so that action now earns nothing.

```html
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Organization",
      "@id": "https://yourproduct.com/#organization",
      "name": "Your Product Ltd",
      "url": "https://yourproduct.com/",
      "logo": {
        "@type": "ImageObject",
        "url": "https://yourproduct.com/static/logo-112.png",
        "width": 112,
        "height": 112
      },
      "sameAs": [
        "https://twitter.com/yourproduct",
        "https://www.linkedin.com/company/yourproduct/"
      ],
      "contactPoint": {
        "@type": "ContactPoint",
        "contactType": "customer support",
        "email": "support@yourproduct.com",
        "url": "https://yourproduct.com/support",
        "areaServed": "GB"
      },
      "address": {
        "@type": "PostalAddress",
        "streetAddress": "12 Example Street",
        "addressLocality": "London",
        "postalCode": "EC1A 1AA",
        "addressCountry": "GB"
      },
      "founder": {
        "@type": "Person",
        "name": "Alex Smith",
        "url": "https://yourproduct.com/about"
      },
      "foundingDate": "2022-04-14",
      "merchantReturnPolicy": {
        "@type": "MerchantReturnPolicy",
        "applicableCountry": "GB",
        "returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow",
        "merchantReturnDays": 30,
        "returnMethod": "https://schema.org/ReturnByMail",
        "returnFees": "https://schema.org/FreeReturn"
      },
      "hasMerchantReturnPolicy": "https://yourproduct.com/legal/returns",
      "shippingDetails": {
        "@type": "OfferShippingDetails",
        "shippingRate": {
          "@type": "MonetaryAmount",
          "value": 0,
          "currency": "GBP"
        },
        "shippingDestination": {
          "@type": "DefinedRegion",
          "addressCountry": "GB"
        }
      }
    },
    {
      "@type": "WebSite",
      "@id": "https://yourproduct.com/#website",
      "url": "https://yourproduct.com/",
      "name": "Your Product",
      "publisher": {
        "@id": "https://yourproduct.com/#organization"
      }
    }
  ]
}
</script>
```

A fixed page has absolute URLs, ISO 8601 dates and crawlable images. The logo is at least 112 by 112 pixels and fetchable by Googlebot.

## Types you will likely use on a product site

- Article, NewsArticle or BlogPosting on /blog/your-post. Include headline, image, datePublished, dateModified and author. Supply several high-resolution images in 16:9, 4:3 and 1:1. Google truncates long headlines.
- Product on /product/sku-abc. For product snippets, name is required and at least one of review, aggregateRating or offers. If you include offers, add price, priceCurrency, availability as a schema.org value like InStock, and url. Add image, brand, sku and gtin if you have them. For merchant listing results, offers can also include shipping and return details.
- SoftwareApplication on /app/your-app. For the software app rich result, set name, offers.price and offers.priceCurrency, and a rating via aggregateRating or a review. applicationCategory and operatingSystem help disambiguate.
- FAQPage on /help/faq. mainEntity is a list of Question with acceptedAnswer of type Answer. As of August 2023, Google shows FAQ rich results only for well-known government and health sites. Your markup stays valid, but expect no FAQ rich result for a product site.
- HowTo on /guides/how-to-do-x. Google removed HowTo rich results in September 2023. The markup is harmless and earns nothing now.
- Organization on the homepage and about pages. Include name, url, logo, sameAs, contactPoint, address, founder and foundingDate. Since 2024, your merchant fields like return policy and shipping can also sit on Organization.
- BreadcrumbList on pages deeper than one level. itemListElement holds ListItem with position starting at 1, name and item. The last item may omit item. Breadcrumbs can replace the URL line in results.
- Review snippet on pages with reviews of supported types like Product or SoftwareApplication. Set itemReviewed to a supported type. For individual reviews, include reviewRating with ratingValue and bestRating and the author name. For aggregateRating include ratingValue and ratingCount or reviewCount. Self-serving reviews for your own LocalBusiness or Organization are not shown as rich results.
- WebSite with SearchAction for internal search. Google removed the sitelinks search box in November 2024, so this now earns nothing. You can still include it for other consumers of schema.

## How to add JSON-LD to your pages

1. **Pick the types that match the page** Decide by intent. /pricing rarely needs Article. /blog/post needs Article and BreadcrumbList. A product page needs Product and Offer.
2. **Draft the graph in a sandbox** Start with the smallest set of required properties. Add recommended fields you actually have. Keep one node per entity, link with @id.
3. **Place the script in the head** Ship it server side where possible. Use application/ld+json as the type. Avoid templating bugs that inject trailing commas.
4. **Fill URLs and dates correctly** Use absolute URLs. Format dates in ISO 8601 like 2026-08-14. Remove currency symbols from numeric fields. Keep rating scales in range.
5. **Deploy on one page** Test on a single URL. Fix every error. Then roll out across the section with templates and data checks.

## How to test JSON-LD today

Use two tools and know the difference. They read the rendered page, so injected markup is visible to them.

- Rich Results Test at search.google.com/test/rich-results. It shows which Google rich results your page is eligible for, and what required or recommended fields are missing for those features.
- Schema Markup Validator at validator.schema.org. It checks your syntax against schema.org. It does not apply Google’s eligibility rules, so it will not tell you if you qualify for a rich result.

The Structured Data Testing Tool closed in 2020. Use the two tools above instead as of 2026.

1. **Run the Rich Results Test** Paste the URL. Check each detected type. Expand errors and warnings. Fix required fields first. Re-test until no errors remain.
2. **Run the Schema Markup Validator** Paste the same URL or your code. Confirm no schema.org errors. If it passes here but fails the Rich Results Test, you are missing Google’s required fields for that feature.
3. **Check the rendered HTML** Open View Source and DevTools Elements. Confirm one script block with your JSON-LD exists and contains valid JSON. Remove duplicates.

## What Search Console shows after you ship

Search Console creates an enhancement report per rich result type detected on your site. You see counts of valid items, warnings and errors by type.

Use the report to track coverage and regressions. Click a problem, inspect a sample URL, fix the template, then click Validate fix to start rechecking.

Not every schema type creates a report. Only supported rich result types do. For example, Organization appears in Google’s knowledge panels, but there is no Organization enhancement report.

## Common errors and quick fixes

- Missing required field. Fix by adding all required properties for the feature, for example Product.name and Offers.priceCurrency.
- Relative URL where absolute is needed. Change "/logo.png" to "https://yourproduct.com/logo.png".
- Date not in ISO 8601. Use "2026-08-14" or a full timestamp. Do not write "14 Sept 2026".
- Price as text with a currency sign. Use "price": 9.99 and "priceCurrency": "USD". Do not write "$9.99" as a string.
- Rating out of range. Keep ratingValue within the stated bestRating and worstRating, or the default 1 to 5.
- Content not visible on the page. Remove markup or add the content users can see. Google requires that marked-up content is visible to users.
- Broken graph. Do not nest types in a way that hides relationships. Prefer separate nodes linked by @id to deep nesting.

> Keep one truth. Do not mark the same entity twice with conflicting facts, for example two Organizations with different names on one page.

## A workflow that scales on a small team

1. **Template per layout** Add JSON-LD once per layout: post, product, docs, homepage. Keep the graph close to the template and test data.
2. **Define required fields as code checks** Fail the build if required fields are missing, or if URLs are not absolute. A pre-commit check catches regressions early.
3. **Log when markup changes** Ship a changelog entry for structured data edits. If clicks drop or rich results vanish, you can link back to a release.
4. **Review in Search Console monthly** Open enhancement reports. Fix new errors. Scan warnings for patterns you can address in content or data quality.

A fixed page in this workflow has one @graph, no console errors, passes validator.schema.org, and shows expected types in the Rich Results Test.

## Questions

### What is JSON-LD used for?

It expresses structured data about your page in a machine readable format. Google reads it to decide eligibility for rich results and to understand entities like your Organization, Product or Article. It lives in a single script block so you can manage it without touching visible HTML.

### What is the difference between JSON and JSON-LD?

JSON is a data format. JSON-LD is JSON with linked data conventions and a context, built to describe entities and their relationships on the web. Search engines read JSON-LD to understand your page. Plain JSON by itself is not structured data for Google.

### Is JSON-LD necessary for SEO?

It is not a ranking factor, but it is the recommended way to add structured data as of 2026. It can earn rich results where your page qualifies, which can raise visibility and click through when shown. It also reduces ambiguity for machines reading your content.

### Where should I put JSON-LD on my page?

Put it in the head. Body also works. Google reads JSON-LD in both places. Server render it where you can. Google renders pages, but many answering AI crawlers do not run scripts, so client only injection can be missed by them.

### How do I verify that my JSON-LD works?

Run the Rich Results Test to see eligibility for Google’s features and to spot missing fields. Run the Schema Markup Validator to confirm your syntax matches schema.org. Then watch Search Console enhancement reports for site wide errors or regressions.

### Can I include several schema types on one page?

Yes. Use one @graph with a node per entity, linked by @id. For example, Organization and WebSite on the homepage, plus BreadcrumbList on deeper pages. On a product page add Product and Offer, and link AggregateRating if you collect it.

## Read next

- [The Rich Results Test: what it checks and what it does not](https://porteur.ai/guides/rich-results-test): Run Google’s Rich Results Test, read eligibility, warnings and errors, know its limits, and when to use schema.org’s validator and Search Console.
- [Organization schema: the fields that feed your knowledge panel](https://porteur.ai/guides/organization-schema): Set up Organization schema to feed your logo, social profiles and knowledge panel. See the fields, a JSON-LD example, where to place it, and how to test.
- [Product schema: the fields Google reads and the ones it requires](https://porteur.ai/guides/product-schema): Set up Product schema that earns snippets and merchant listings. See the required fields, the recommended ones and a full JSON-LD example.
- [SoftwareApplication schema for a SaaS: an example that validates](https://porteur.ai/guides/softwareapplication-schema): Add SoftwareApplication schema that passes Google’s Rich Results Test. See the required fields, a clean SaaS example, and how to test and ship it.
- [Article schema: headline, images, dates and author, done right](https://porteur.ai/guides/article-schema): Use Article, BlogPosting or NewsArticle schema the way Google expects. Get headlines, images, dates and the author right, and test it before release.
- [Structured data](https://porteur.ai/glossary/structured-data): Structured data is schema markup that names your page type. See why it changes results, how to add JSON-LD, and how to validate it.

Get a free check of your JSON-LD from your URL. In about thirty seconds it reads your site, the searches around it and the rivals on them, and shows three findings whole. Free check: https://porteur.ai/
