citare
SEO

JSON-LD

JSON-LD (JSON for Linked Data) is the W3C-standard serialization format for embedding structured data in HTML pages — a JSON object wrapped in a script tag that declares schema.org vocabulary describing the page's content and entities.

Definition

JSON-LD is a JSON-based serialization of linked data, designed to be embedded in HTML pages as a discrete <script type="application/ld+json"> block in the head or body. Unlike microdata or RDFa, JSON-LD doesn't intermingle with the page's visible content — the structured-data layer lives separately from the rendered HTML.

Basic shape

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "What JSON-LD is",
  "datePublished": "2026-05-22",
  "author": {
    "@type": "Organization",
    "name": "Citare",
    "url": "https://citare.ai"
  }
}
</script>

The @context field declares the vocabulary (almost always schema.org). The @type field declares what kind of thing this block describes. The remaining fields are properties of that type.

Why JSON-LD over microdata or RDFa

  • Separation of concerns. Schema metadata lives in a script tag, page content lives in normal HTML. Edits to one don't break the other.
  • Easier validation. A single JSON parse confirms the block is well-formed. Microdata bugs (missing closing tags, mistyped itemprop names) are harder to catch.
  • Google's preferred format. Documented preference in Search Central since 2017. Tools mature around it.
  • Multiple blocks per page. A page can have an Organization schema, an Article schema, a FAQPage schema, and a BreadcrumbList schema as separate script tags without conflict.

@graph composite pattern

When a page has multiple related entities (e.g., an Article and its Author and the Publishing Organization), the @graph wrapper lets them reference each other via @id URIs:

{
  "@context": "https://schema.org",
  "@graph": [
    { "@type": "Organization", "@id": "https://citare.ai#org", "name": "Citare" },
    { "@type": "Person", "@id": "https://citare.ai#author-ravi", "name": "Ravi" },
    { "@type": "Article", "author": { "@id": "https://citare.ai#author-ravi" }, "publisher": { "@id": "https://citare.ai#org" } }
  ]
}

This pattern avoids duplicating entity definitions across pages and lets crawlers consolidate signals properly.

Critical escaping pitfall

If a JSON-LD answer string contains the literal characters </, the browser interprets it as the closing </script> tag and terminates the JSON block early. Fix: escape every </ to <\/ before serializing.

Citare's marketing build does this automatically via serializeSchema() in src/lib/marketing/schema.ts. Manual implementations need the same step.

Validation tools

  • Google Rich Results Test — validates against Google's specific feature requirements
  • Schema.org Validator — generic schema.org validation
  • JSON-LD Playground — graph visualization and processing

See /tools/json-ld-inspector for the free inspector tool.

Frequently asked

Where should JSON-LD blocks be placed in the HTML — head or body?

Either works. Google recommends head for performance (parses before render), but body placement is valid and common. Multiple blocks per page is also fine — Google merges them when interpreting the structured data.

How do I escape JSON-LD content that includes HTML tags like '<head>'?

Replace every occurrence of '</' with '<\\/' before serializing. Without this, a string like 'inside the <head> tag' will accidentally close the script block when the browser encounters '</'. The literal output should be the backslash-forward-slash, which the browser unescapes back to /.

Can the same page have multiple @type values?

Yes, two ways. One: separate <script> blocks for each type. Two: a single @graph block with multiple entities. The @graph approach is cleaner when entities reference each other via @id.

Related

Stop guessing where you rank in AI search

Citare measures citation rate and share of voice across ChatGPT, Google AI Overview, Gemini, Claude, and Perplexity — weekly, for your priority queries. Free forever tier.