← Oleksii Turovskyi

How to Help AI Understand Your Content with JSON-LD

· 8 min read

When an extension reports that there's no valid JSON-LD with core entities (Article, FAQPage, Product) on a page, that's not a cosmetic defect. It's a signal. Large language models and systems like Google AI Overviews see your page as a bag of unconnected tokens, not as a structured object with a clearly tagged author, publish date, headline, price, or answer to a specific question.

Without markup, the model guesses. With markup, it knows.

1. Why LLMs critically depend on structured data#

Large language models generate text based on probabilities, but when a query touches facts — a specific author, a date, a price, an answer — they fall back on what Google calls grounding (anchoring an answer in a source). JSON-LD becomes that source of truth in a machine-readable format.

A few concrete mechanisms worth understanding:

  • AI Overviews and generative search lift paragraphs and facts off pages. Structured markup substantially raises the chance that your content is selected as the citation source rather than a competitor's content the model had to parse from "naked" HTML.
  • Schema.org remains the shared vocabulary. Search engines, LLM parsers, voice assistants, and AI-platform crawlers all understand it — from ChatGPT to Perplexity.
  • Precision without NLP extraction. Without markup, the model extracts entities through NLP analysis. It works, but unpredictably. Through JSON-LD you hand the model unambiguous fields: this is headline, this is author, this is datePublished. No room for interpretation.

An important nuance about FAQPage: in August 2023, Google began showing FAQ rich-result snippets only for authoritative government and medical sites. But FAQ markup has one of the highest citation rates among types of structured data. Pages with FAQPage are 3.2× more likely to land in Google AI Overviews. So FAQPage today works not for classic SERP, but for AI channels.

The analogy is simple. HTML is a page layout for humans. JSON-LD is the same content rewritten in a format that leaves machines no room for guesswork.

2. The right example: Article + FAQPage via @graph#

Mark up a <script type="application/ld+json"> block in <head> or near the end of <body>. You can use multiple separate scripts — or unite the entities into a single @graph. The second option is cleaner: it lets you connect objects via @id.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Article",
      "@id": "https://example.com/posts/json-ld-guide#article",
      "headline": "How to help AI understand your content with JSON-LD",
      "description": "A step-by-step guide on adding structured data for AI Overviews and LLMs.",
      "image": [
        "https://example.com/images/cover-1x1.jpg",
        "https://example.com/images/cover-4x3.jpg",
        "https://example.com/images/cover-16x9.jpg"
      ],
      "datePublished": "2026-05-01T08:00:00+00:00",
      "dateModified": "2026-05-01T08:00:00+00:00",
      "inLanguage": "en-US",
      "author": {
        "@type": "Person",
        "name": "Olena Koval",
        "url": "https://example.com/authors/olena-koval"
      },
      "publisher": {
        "@type": "Organization",
        "name": "Example Media",
        "logo": {
          "@type": "ImageObject",
          "url": "https://example.com/logo.png"
        }
      },
      "mainEntityOfPage": {
        "@type": "WebPage",
        "@id": "https://example.com/posts/json-ld-guide"
      }
    },
    {
      "@type": "FAQPage",
      "@id": "https://example.com/posts/json-ld-guide#faq",
      "mainEntity": [
        {
          "@type": "Question",
          "name": "Does JSON-LD replace Microdata markup?",
          "acceptedAnswer": {
            "@type": "Answer",
            "text": "Yes. Google recommends JSON-LD as the primary format for structured data. Microdata remains valid, but JSON-LD is easier to maintain — it's decoupled from HTML markup and doesn't break during redesigns."
          }
        },
        {
          "@type": "Question",
          "name": "Will an LLM see my markup if it renders via JavaScript?",
          "acceptedAnswer": {
            "@type": "Answer",
            "text": "Most modern crawlers do execute JS, but the reliable path is to ship JSON-LD in the initial HTML — via SSR or static generation. That way you avoid render races and guarantee inclusion in AI-platform indexes."
          }
        },
        {
          "@type": "Question",
          "name": "Will I get a FAQ rich snippet in Google search?",
          "acceptedAnswer": {
            "@type": "Answer",
            "text": "No, unless your site is in an authoritative government or medical category. But FAQPage is still worth adding — AI Overviews, ChatGPT, Perplexity, and Gemini actively pull content from this markup."
          }
        }
      ]
    }
  ]
}
</script>

A few principles that make this block actually useful, not decorative:

  • @graph lets you place several entities in a single script and connect them via @id. Cleaner than two separate tags.
  • @id is not the page URL, it's a unique identifier for the entity. The hash fragment (#article, #faq) makes it stable.
  • mainEntityOfPage ties Article to a specific canonical URL.
  • image as an array with three aspect ratios (1:1, 4:3, 16:9) is a direct Google requirement for getting Article rich results.
  • inLanguage helps LLM platforms understand the content language and correctly cite it in language-specific queries.

Implementation in Next.js (App Router)#

A working page example for Next.js 16 with Tailwind CSS. The key technical decision here is using JSON.stringify instead of a template literal to safely escape data.

app/posts/[slug]/page.tsx
import type { Metadata } from "next";
 
interface PageProps {
  params: Promise<{ slug: string }>;
}
 
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
  const { slug } = await params;
  return {
    title: `Article ${slug}`,
    alternates: { canonical: `https://example.com/posts/${slug}` },
  };
}
 
export default async function PostPage({ params }: PageProps) {
  const { slug } = await params;
  const canonicalUrl = `https://example.com/posts/${slug}`;
 
  const jsonLd = {
    "@context": "https://schema.org",
    "@graph": [
      {
        "@type": "Article",
        "@id": `${canonicalUrl}#article`,
        "headline": "How to help AI understand your content with JSON-LD",
        "description":
          "A step-by-step guide on adding structured data for AI Overviews and LLMs.",
        "image": [
          "https://example.com/images/cover-1x1.jpg",
          "https://example.com/images/cover-4x3.jpg",
          "https://example.com/images/cover-16x9.jpg",
        ],
        "datePublished": "2026-05-01T08:00:00+00:00",
        "dateModified": "2026-05-01T08:00:00+00:00",
        "inLanguage": "en-US",
        "author": {
          "@type": "Person",
          "name": "Olena Koval",
          "url": "https://example.com/authors/olena-koval",
        },
        "publisher": {
          "@type": "Organization",
          "name": "Example Media",
          "logo": {
            "@type": "ImageObject",
            "url": "https://example.com/logo.png",
          },
        },
        "mainEntityOfPage": {
          "@type": "WebPage",
          "@id": canonicalUrl,
        },
      },
      {
        "@type": "FAQPage",
        "@id": `${canonicalUrl}#faq`,
        "mainEntity": [
          {
            "@type": "Question",
            "name": "Does JSON-LD replace Microdata markup?",
            "acceptedAnswer": {
              "@type": "Answer",
              "text": "Yes — Google recommends JSON-LD as the primary format. Microdata is still valid, but JSON-LD is easier to maintain because it's decoupled from HTML.",
            },
          },
          {
            "@type": "Question",
            "name": "Will an LLM see my markup if it renders via JavaScript?",
            "acceptedAnswer": {
              "@type": "Answer",
              "text": "The reliable path is to ship JSON-LD in the initial HTML — via SSR or static generation.",
            },
          },
        ],
      },
    ],
  };
 
  return (
    <>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
      />
      <article className="max-w-3xl mx-auto py-10 px-4 sm:px-6 lg:px-8">
        <header className="mb-8">
          <h1 className="text-3xl font-bold tracking-tight text-gray-900">
            How to help AI understand your content with JSON-LD
          </h1>
          <div className="mt-2 text-sm text-gray-500">
            <time dateTime="2026-05-01T08:00:00+00:00">May 1, 2026</time>
          </div>
        </header>
        <div className="prose prose-blue lg:prose-lg">
          <p>
            Correct data structure is foundational for effective interaction
            with AI algorithms. Without it, crawlers fall back on basic NLP
            text analysis.
          </p>
          <h2>Adding the markup</h2>
          <p>
            Using a built-in script of type <code>application/ld+json</code>{" "}
            guarantees that search systems can identify entities on your page
            without ambiguity.
          </p>
        </div>
      </article>
    </>
  );
}

3. How to verify validity without extra tools#

You don't need a local CLI or a SaaS to confirm your markup is valid. Three official steps are enough.

Step 1. Browser DevTools — instant presence check#

Open the page, run this snippet in the console:

browser-devtools-jsonld-check.js
const blocks = document.querySelectorAll('script[type="application/ld+json"]');
console.log(`JSON-LD blocks found: ${blocks.length}`);
 
blocks.forEach((block, i) => {
  try {
    const parsed = JSON.parse(block.textContent);
    console.group(`Block #${i + 1}`);
    console.log(parsed);
 
    if (parsed["@graph"]) {
      const types = parsed["@graph"].map((item) => item["@type"]);
      console.log("Entity types in @graph:", types);
    } else if (parsed["@type"]) {
      console.log("Entity type:", parsed["@type"]);
    }
 
    console.groupEnd();
  } catch (err) {
    console.error(`Block #${i + 1} contains invalid JSON:`, err.message);
  }
});

The snippet instantly shows: how many blocks there are, whether each parses, what entities it contains. If the counter reads zero — the extension was right, there's no markup. If JSON.parse throws — you have broken syntax, and no validator further down the line will help until you fix it.

Step 2. Schema Markup Validator — syntax and vocabulary#

Visit validator.schema.org. It's the tool from the schema.org community itself. It checks JSON-LD syntax against the vocabulary, shows every entity it found, fields, and unknown properties. A baseline check, not tied to any specific search engine.

Step 3. Rich Results Test — Google's-eye view#

Go to search.google.com/test/rich-results. Google's tool renders your page as Googlebot, executes JavaScript, and shows which rich results your content is potentially eligible for. This is where you catch issues Schema Validator misses: missing required fields for a specific type (for example, missing image on Article) or post-JS-render errors.

Order, and why it matters:

  1. DevTools snippet — confirm the blocks even reach the rendered page.
  2. Schema Markup Validator — verify syntax and vocabulary conformance.
  3. Rich Results Test — verify what Google sees after rendering.

Green across all three and your content is ready for AI Overviews, ChatGPT, Perplexity, and classic Google search to read it precisely — not paraphrase it approximately.


Is your site still losing AI traffic to invisible content?

Follow me on LinkedIn to keep up with new AEO-architecture standards. If you're looking for an experienced architect for a platform audit, deep schema implementation, or headless-architecture optimization — get in touch for consulting.