JSON-LD Structured Data: A Practical Guide for Developers

In this article10 sections
JSON-LD structured data is machine-readable information about a page, written as a JSON object inside a script tag, that tells search engines what the page represents: an organisation, an article, a product, a breadcrumb trail or a list of questions. Google recommends JSON-LD because it keeps the markup separate from the visible HTML, which makes it easier to generate and maintain.
Structured data can make pages eligible for rich results, such as breadcrumbs, product details or article information, but it does not guarantee them, and it does not directly improve rankings. Its value is clarity: when markup accurately describes the content people can see, search engines understand the page with less guesswork.
This guide covers the types most business websites need, how to build them from your own data in PHP, the rules that keep markup eligible and the tools for testing it.
Key takeaways
- Google recommends JSON-LD, placed in a script tag in the head or body.
- Markup must describe content that is visible on the page, accurately and completely.
- Most business sites need Organization, WebSite, BreadcrumbList and Article or Service markup.
- Rich results are never guaranteed, and some types are limited to specific kinds of sites.
- Generate markup from the same data as the page, then test it automatically.
Why JSON-LD structured data is recommended
Google's introduction to structured data explains that Google supports JSON-LD, Microdata and RDFa, and recommends JSON-LD. Microdata and RDFa weave attributes into the visible HTML, so a template change can silently break them. JSON-LD sits in its own script block, built from data, and can be tested independently of the design.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"@id": "https://example.com/#organization",
"name": "Example Technologies",
"url": "https://example.com/",
"logo": "https://example.com/assets/logo.png",
"sameAs": ["https://www.linkedin.com/company/example"]
}
</script>
The vocabulary comes from Schema.org. Google supports only part of it for rich results, and documents the required and recommended properties for each feature it supports.
The types most business sites need
| Type | Where | What it helps with |
|---|---|---|
| Organization | Every page, usually from the layout | Name, logo, contact details and social profiles of the business |
| WebSite | Home page or every page | The site name Google may show in results |
| BreadcrumbList | Pages below the home page | Breadcrumb trails in results instead of raw URLs |
| Article or BlogPosting | Blog posts and news | Headline, author, dates and images |
| Product | Product pages | Price, availability and reviews where eligible |
| Service | Service pages | Describes services and the areas served (no specific rich result) |
| LocalBusiness | Real office or shop locations | Address, opening hours and geographic details |
Product markup has its own detailed rules; our guide to product schema markup covers it for online stores.
Start with the types that match your templates rather than trying to mark up everything. A typical business site has a handful of templates: home, service, article, contact and perhaps product. Adding the right markup to each template covers every page built from it, and it is far easier to keep accurate than page-by-page additions.
Building a connected graph
Rather than scattering unrelated objects across a page, connect them with @id references. The organisation is defined once and referenced as the publisher of articles and the provider of services. This avoids duplicate, slightly different descriptions of the same business.
{
"@context": "https://schema.org",
"@graph": [
{ "@type": "WebSite", "@id": "https://example.com/#website",
"url": "https://example.com/", "name": "Example Technologies",
"publisher": { "@id": "https://example.com/#organization" } },
{ "@type": "BlogPosting", "@id": "https://example.com/blog/xml-sitemaps#article",
"headline": "XML Sitemaps Done Right",
"datePublished": "2026-10-23T10:00:00+05:30",
"dateModified": "2026-10-23T10:00:00+05:30",
"author": { "@type": "Person", "name": "Jane Developer" },
"publisher": { "@id": "https://example.com/#organization" },
"image": "https://example.com/uploads/sitemaps-cover-1600.webp" }
]
}
Use absolute URLs for every @id, url and image. Keep identifiers stable, so the same entity always has the same @id across pages. A common convention is the page URL followed by a fragment such as #organization or #article.
Generating markup in PHP
Build structured data as PHP arrays from the same records that render the page, then encode once. Hand-written JSON in templates drifts out of date as soon as content editors change a title or price.
// Build BreadcrumbList from the same items the visible breadcrumb uses.
function breadcrumbSchema(array $items): array {
$list = [];
foreach (array_values($items) as $i => [$name, $path]) {
$entry = ['@type' => 'ListItem', 'position' => $i + 1, 'name' => $name];
if ($path !== null) {
$entry['item'] = url($path);
}
$list[] = $entry;
}
return ['@type' => 'BreadcrumbList', 'itemListElement' => $list];
}
$json = json_encode(['@context' => 'https://schema.org', '@graph' => $graph],
JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_HEX_TAG);
The JSON_HEX_TAG flag escapes angle brackets, so text containing </script> cannot break out of the script block. Collect objects from the layout and the page into one graph, and output a single script tag per page.
Keep the builders small and testable: one function per type, taking plain data and returning an array. Templates then only decide which builders to call. When Google changes a requirement, you update one function rather than searching through views for scattered JSON fragments.
Rules that keep markup eligible
Google's structured data guidelines apply to every type. Breaking them can make a page ineligible for rich results, and serious abuse can lead to a manual action.
- Describe visible content: do not mark up reviews, prices or questions that users cannot see on the page.
- Be accurate and current: prices, availability and dates must match the page exactly.
- Be specific: mark up the main entity of the page, not every item that happens to be mentioned.
- Include required properties for each feature, and as many recommended ones as you can fill honestly.
- Do not self-review: review markup about your own business on your own site is not eligible for review rich results.
Features with limited eligibility
Some rich results are restricted. FAQ rich results, for example, are now shown only for well-known, authoritative government and health websites, and How-to rich results have been retired. FAQPage markup is still valid and harmless on other sites, and it can still help search engines understand question-and-answer content, but do not expect expandable FAQs under your result.
Service and location markup
Service businesses often ask which type to use for their service pages. Schema.org has a Service type that describes what is offered, who provides it and where. Google does not show a specific rich result for it, but it is a clear, honest description of the page and links naturally to your Organization through the provider property.
{
"@type": "Service",
"@id": "https://example.com/services/magento-development#service",
"name": "Magento development",
"serviceType": "Magento development",
"provider": { "@id": "https://example.com/#organization" },
"areaServed": [{ "@type": "Country", "name": "India" }, { "@type": "Country", "name": "United Arab Emirates" }]
}
For physical locations, LocalBusiness or a more specific subtype describes an address customers can visit, with opening hours and coordinates. Use it only for real premises. Pages that describe a market you serve remotely should not claim a local address there; describe the area served instead. Keep the details identical to your Google Business Profile, so the two sources reinforce each other.
Keeping structured data in sync
The most common structured data problem is not invalid syntax but stale data: a price that changed on the page and not in the markup, an author who left, a logo URL that now returns 404. Treat markup as part of the content model, not as decoration.
- One source of truth: build every value from the same fields the page displays.
- Dates from content timestamps: use publication and content-update dates, not the time of the request.
- Images that exist: reference the same optimised image the page shows, at a size Google can actually use.
- Review after redesigns: template changes often remove the include that outputs the script tag.
A nightly job that fetches a sample of URLs per template and validates their JSON-LD against your own rules catches most drift long before it shows up in Search Console.
Site names and organisation details
Google uses WebSite structured data, along with other signals, to choose the site name shown above search results. Google's documentation on site names recommends marking up the home page with the name you want and keeping it consistent with the name used on the site.
- Use the same organisation name in WebSite, Organization, the page title and visible branding.
- Provide a logo URL that points to a crawlable, square-friendly image.
- List official social profiles in
sameAs, and only profiles you actually control and keep active. - Add contact points and addresses only where they are accurate and public.
Testing and monitoring structured data
- Use the Rich Results Test on representative URLs of each template.
- Validate general Schema.org syntax with the Schema Markup Validator for types Google does not support as rich results.
- Write unit tests that decode each template's JSON-LD and assert required properties exist and match the page data.
- Check Search Console enhancement reports after releases for new errors and warnings.
- Use the URL Inspection tool to confirm Google sees the markup in the rendered page.
On JavaScript-heavy sites, include structured data in the server response where possible. Our guide to JavaScript SEO explains why markup injected late can be missed. And remember that structured data supports, but does not replace, a clear title and description; our guide to title tags and meta descriptions covers those.
Frequently asked questions
Does structured data improve rankings?
Not directly. It helps search engines understand content and can make pages eligible for rich results, which may improve how results look.
Should I use JSON-LD or Microdata?
Google recommends JSON-LD because it is easier to generate and maintain separately from the visible HTML.
Why does my FAQ markup not show in results?
FAQ rich results are now limited to well-known government and health websites. The markup is still valid, but most sites will not see the feature.
Can I add structured data with Google Tag Manager?
It can work, but markup rendered by scripts is less reliable. Server-generated JSON-LD is easier to test and keep accurate.
Want structured data that stays correct as your site changes? Our SEO services include structured data audits, and our developers can build it into your templates.
Want an expert to look at your store?
Tell us what you are working on. A senior e-commerce consultant will reply within one working day with honest, practical advice. No obligation and no sales script.
- Reply within one working day
- Advice even if we are not the right fit
- Your details are never shared