JSON-LD for AI Search: 7 Mistakes That Block Citations
Most structured data audits end the same way: the validator says zero errors , the Rich Results Test passes, and six months later the site has still never appeared in a single ChatGPT or Perplexity answer. I have gone through this with enough sites now to say it plainly — the problem is almost neve

Die meisten Audits strukturierter Daten enden auf dieselbe Weise: Der Validator meldet null Fehler, der Rich Results Test besteht, und sechs Monate später ist die Website dennoch nie in einer einzigen ChatGPT- oder Perplexity-Antwort erschienen.
Ich habe diesen Prozess inzwischen mit genug Websites durchlaufen, um es klar zu sagen: Das Problem ist fast nie die Syntax. Es liegt daran, dass das Markup eine Seite beschreibt, während das Retrieval-System nach einer Entität sucht, und der tatsächliche Inhalt der Seite den Crawler ohnehin nie erreicht.
Hier sind die sieben Fehler, die ich immer wieder sehe, sortiert nach dem Schaden, den sie anrichten.
Das Standardmuster ist ein einzelner WebPage-Block. Das teilt einer Maschine mit: Dies ist eine Seite vom Typ WebPage, was ungefähr so nützlich ist wie der Hinweis, dies sei eine Datei.
Retrieval- und Grounding-Systeme müssen auflösen, wer du bist, nicht welcher Tag die URL umschließt. Es gibt keinen Weg von WebPage zu einem Knoten im Knowledge Graph.
{ "@context": "https://schema.org", "@type": "WebPage", "name": "Acme Analytics — Product Page", "url": "https://acme.dev/product" } Vollbildmodus öffnen Vollbildmodus schließen Nach
sameAs ist das günstigste Disambiguierungssignal, das es gibt, und zugleich das, das am häufigsten weggelassen wird.
Wird ein LLM gefragt, was Acme Analytics ist, hat es keine Möglichkeit zu erkennen, dass deine Domain die Autorität zu Acme Analytics ist. Es weiß sehr wohl, was eine GitHub-Organisation, ein Crunchbase-Eintrag und ein Wikidata-Item sind. sameAs ist die Brücke, die du ihm dabei in die Hand gibst.
Das ist der stille Killer bei Next.js, Nuxt, React-SPAs und allem, was eine Head-Management-Bibliothek verwendet.
Wenn dein Schema so auf die Seite gelangt:
Die Lösung ist unspektakulär: Serialisiere das JSON serverseitig und rendere es als statischen Text im Dokument.
// ✅ in der rohen HTML-Antwort vorhanden const jsonLd = JSON. stringify ( schema, null, 2 ); return ( < script type = " application/ld+json " dangerouslySetInnerHTML = {{ __html: jsonLd }} / > ); Vollbildmodus öffnen Vollbildmodus schließen Verifiziere es auf die einzige Weise, die zählt, also nicht in den DevTools, sondern in der tatsächlichen Antwort:
curl -s https://acme.dev/product | grep -c 'application/ld+json' Vollbildmodus öffnen Vollbildmodus schließen Liefert das 0 zurück, während der Browser ein valides Schema zeigt, hast du deinen Fehler gefunden.
Gleiche Ursache wie bei Punkt 3, nur mit weit schlimmeren Folgen. Schema ist Metadaten. Der Inhalt ist das, was eingebettet und zitiert wird.
Wenn dein Produkttext, der Dokumentationskörper oder der Artikeltext clientseitig gerendert wird, lieferst du jedem Crawler, der keinen Browser ausführt, eine leere Hülle aus.
# Vergleiche, was ein Crawler sieht vs. was ein Nutzer sieht curl -s -A "GPTBot" https://acme.dev/docs/getting-started | wc -w curl -s https://acme.dev/docs/getting-started | wc -w Vollbildmodus öffnen Vollbildmodus schließen Eine Differenz von 30 Wörtern ist ein Widget. Eine Differenz von 900 Wörtern bedeutet, dass deine Dokumentation aus Sicht des Retrievals nicht existiert, egal wie gut dein JSON-LD ist.
Die praktische Antwort ist SSR, SSG oder ISR für jede Route, die zitiert werden soll. Clientseitig gerenderte Routen sind für den Anwendungszustand da, nicht für veröffentlichte Inhalte.
Validatoren prüfen die Form, nicht die Bedeutung. All das hier besteht die Prüfung und verschlechtert dennoch das Ergebnis:
ISO-Daten sind wichtiger, als sie aussehen. "Oct 24, 2026" ist mehrdeutig genug, dass einige Parser das Feld komplett verwerfen, und dateModified ist eines der wenigen Frische-Signale, das du vollständig selbst kontrollierst.
Hier werden ständig zwei verschiedene Fehler gemacht.
Fehler A, die fehlerhafte Struktur. mainEntity muss ein Array aus Question-Objekten sein, jeweils mit einem verschachtelten acceptedAnswer vom Typ Answer. Ein flaches {"question": "...", "answer": "..."} ist kein Schema.org.
{ "@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [ { "@type": "Question", "name": "Does JSON-LD improve AI search visibility?", "acceptedAnswer": { "@type": "Answer", "text": "JSON-LD does not directly improve rankings, but it removes ambiguity about what a page and its publisher are, which helps retrieval systems select the page as a source." } } ] } Vollbildmodus öffnen Vollbildmodus schließen Fehler B, die nicht zusammenpassenden Paare. Die Frage im Markup muss von dem Text beantwortet werden, der auf der Seite darauf folgt. Sagt die ausgezeichnete Frage etwa "How much does it cost?" und die sichtbare Antwort handelt vom Onboarding, hast du ein falsches Paar erzeugt.
Das ist schlimmer als gar kein Markup, denn jetzt hat das System eine confident falsche Antwort, die dir zugeschrieben wird.
Eine ehrliche Einschränkung: Google hat FAQ-Reichergebnisse bereits 2023 auf autoritative Regierungs- und Gesundheitsseiten beschränkt und HowTo-Reichergebnisse vollständig entfernt. Dieses Markup bringt dir also kein SERP-Feature. Was es weiterhin leistet, sind saubere, in sich geschlossene Frage-Antwort-Abschnitte, die Retrieval-Pipelines übernehmen können, ohne deinen umgebenden Fließtext parsen zu müssen. Das ist der Grund, es beizubehalten, nicht das Reichergebnis.
Man boltet ein Plugin an, fügt später ein zweites hinzu, und am Ende hat man zwei Organization-Blöcke pro Seite, die unterschiedliche Dinge sagen:
{ "@type": "Organization", "name": "Acme Ltd" } { "@type": "Organization", "name": "Acme Analytics Inc.", "url": "https://www.acme.dev" } Vollbildmodus öffnen Vollbildmodus schließen Für ein abgleichendes System sind das zwei Unternehmen. Die Konsolidierung schlägt still fehl, und nirgends erhältst du eine Fehlermeldung.
Lege kanonische Werte einmal fest, also exakter rechtlicher Name, exakte kanonische URL, exaktes Logo, und verwende sie in <title>, og:title und in jedem Organization-Knoten. Dann dedupliziere:
# Sollte genau 1 pro Seite zurückgeben curl -s https://acme.dev/ | grep -o '"@type":"Organization"' | wc -l Vollbildmodus öffnen Vollbildmodus schließen Die 5-Minuten-Audit-Reihenfolge Wenn du nach der Lektüre nur fünf Dinge tust:
Beachte, dass keine dieser Maßnahmen den Rich Results Test einbezieht. Der sagt dir nur, dass das Markup wohlgeformt ist, was nie die Frage war.
Sollte ich GPTBot blockieren? GPTBot ist OpenAIs Training-Crawler. Er ist getrennt von OAI-SearchBot, der die ChatGPT-Suche betreibt, und von ChatGPT-User, der ausgelöst wird, wenn ein Nutzer ChatGPT bittet, eine URL abzurufen. GPTBot zu blockieren entfernt dich nicht aus den ChatGPT-Suchergebnissen. OAI-SearchBot zu blockieren schon. Triff diese Entscheidung bewusst, statt ein robots.txt-Snippet aus einem Blogbeitrag zu kopieren.
Bringt FAQPage-Markup noch etwas? Nicht für Reichergebnisse auf den meisten Websites. Es erzeugt weiterhin saubere Frage-Antwort-Paare, die sich beim Retrieval mühelos chunkieren lassen, was ein echter, wenn auch bescheidener Nutzen ist.
Wie lange dauert es, bis strukturierte Daten eine Wirkung zeigen? Die Recrawl-Frequenz ist der begrenzende Faktor, nicht das Markup. Crawler besuchen beliebte Seiten innerhalb von Tagen erneut, Seiten mit wenig Traffic innerhalb von Wochen bis Monaten. Rechne mit einem Quartal, nicht mit einer Woche, und verfolge die Bot-Treffer in den Server-Logs, statt es aus dem Traffic abzuleiten.
Wenn du die vollständige Version dieses Audits als einziges Dokument möchtest, also alle sieben Prüfungen ausgebaut zu einer 100-Punkte-Bereitschaftsliste, dazu die vollständigen JSON-LD-Templates für Organization-, SoftwareApplication-, Article-, Person- und FAQPage-Graphen, bereits verdrahtet mit @id-Querverweisen, habe ich es hier zusammengestellt: * Structured for Answers → ***
Als Nächstes in dieser Serie: Wie du testest, ob AI-Crawler deine Website wirklich lesen können, also die acht Prüfungen, die dir zeigen, wo du tatsächlich stehst, bevor du auch nur eine Zeile Markup änderst.
Automatisch übersetzt. Das Original auf Englisch ist unten aufklappbar.
Original (Englisch) anzeigen
Most structured data audits end the same way: the validator says zero errors, the Rich Results Test passes, and six months later the site has still never appeared in a single ChatGPT or Perplexity answer.
I have gone through this with enough sites now to say it plainly — the problem is almost never syntax. It is that the markup describes a page when the retrieval system is looking for an entity, and the page's actual content never reaches the crawler in the first place.
Here are the seven failures I see repeatedly, in the order they cost you the most.
The default pattern is a single WebPage block. That tells a machine "this is a page of the type WebPage" — which is roughly as useful as telling it "this is a file."
Retrieval and grounding systems need to resolve who you are, not what tag wraps the URL. There is no path from WebPage to a knowledge graph node.
{ "@context": "https://schema.org", "@type": "WebPage", "name": "Acme Analytics — Product Page", "url": "https://acme.dev/product" } Enter fullscreen mode Exit fullscreen mode After
sameAs is the cheapest disambiguation signal that exists and it is the one most often skipped.
An LLM asked "what is Acme Analytics" has no way to know your domain is the authority on Acme Analytics. It does know what a GitHub org, a Crunchbase entry, and a Wikidata item are. sameAs is how you hand it the bridge.
This is the quiet killer on Next.js, Nuxt, React SPAs, and anything using a head-management library.
If this is how your schema gets onto the page:
The fix is boring: serialize the JSON server-side and render it as static text in the document.
// ✅ present in the raw HTML response const jsonLd = JSON. stringify ( schema, null, 2 ); return ( < script type = " application/ld+json " dangerouslySetInnerHTML = {{ __html: jsonLd }} / > ); Enter fullscreen mode Exit fullscreen mode Verify it in the only way that counts — not in DevTools, but in the actual response:
curl -s https://acme.dev/product | grep -c 'application/ld+json' Enter fullscreen mode Exit fullscreen mode If that returns 0 while the browser shows valid schema, you've found your bug.
Same root cause as #3, much worse consequence. Schema is metadata. Content is what gets embedded and cited.
If your product copy, documentation body, or article text renders client-side, you are shipping an empty shell to every crawler that doesn't run a browser.
# Compare what a crawler sees vs what a user sees curl -s -A "GPTBot" https://acme.dev/docs/getting-started | wc -w curl -s https://acme.dev/docs/getting-started | wc -w Enter fullscreen mode Exit fullscreen mode A 30-word difference is a widget. A 900-word difference means your documentation does not exist as far as retrieval is concerned — no matter how good your JSON-LD is.
The practical answer is SSR, SSG, or ISR for every route you want cited. Client-rendered routes are for app state, not published content.
Validators check shape, not meaning. These all pass and all degrade the output:
ISO dates matter more than they look. "Oct 24, 2026" is ambiguous enough that some parsers drop the field entirely, and dateModified is one of the few freshness signals you fully control.
Two separate mistakes get made here constantly.
Mistake A — malformed structure. mainEntity must be an array of Question objects, each with a nested acceptedAnswer of type Answer. A flat {"question": "...", "answer": "..."} is not Schema.org.
{ "@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [ { "@type": "Question", "name": "Does JSON-LD improve AI search visibility?", "acceptedAnswer": { "@type": "Answer", "text": "JSON-LD does not directly improve rankings, but it removes ambiguity about what a page and its publisher are, which helps retrieval systems select the page as a source." } } ] } Enter fullscreen mode Exit fullscreen mode Mistake B — mismatched pairs. The question in the markup has to be answered by the text that follows it on the page. If the marked-up question says "How much does it cost?" and the visible answer is about onboarding, you have created a false pair. That is worse than no markup, because now the system has a confident wrong answer attributed to you.
One honest caveat: Google restricted FAQ rich results to authoritative government and health sites back in 2023, and removed HowTo rich results entirely. So this markup will not give you a SERP feature. What it still does is produce clean, self-contained question-answer chunks that retrieval pipelines can pull without parsing your surrounding prose. That's the reason to keep it — not the rich result.
Bolt on a plugin, add a second one later, and you end up with two Organization blocks per page saying different things:
{ "@type": "Organization", "name": "Acme Ltd" } { "@type": "Organization", "name": "Acme Analytics Inc.", "url": "https://www.acme.dev" } Enter fullscreen mode Exit fullscreen mode To a reconciling system this is two companies. Consolidation fails silently and you get no error anywhere.
Pick canonical values once — exact legal name, exact canonical URL, exact logo — and use them in <title>, og:title, and every Organization node. Then dedupe:
# Should return exactly 1 per page curl -s https://acme.dev/ | grep -o '"@type":"Organization"' | wc -l Enter fullscreen mode Exit fullscreen mode The 5-minute audit order If you only do five things after reading this:
Notice that none of these involve the Rich Results Test. It tells you the markup is well-formed, which was never the question.
Should I block GPTBot? GPTBot is OpenAI's training crawler. It is separate from OAI-SearchBot, which handles ChatGPT search, and ChatGPT-User, which fires when a user asks ChatGPT to fetch a URL. Blocking GPTBot does not remove you from ChatGPT search results. Blocking OAI-SearchBot does. Make that decision deliberately rather than copying a robots.txt snippet from a blog post.
Does FAQPage markup still do anything? Not for rich results on most sites. It still produces clean question-answer pairs that are trivial to chunk during retrieval, which is a real but modest benefit.
How long until structured data shows an effect? Recrawl cadence is the limiter, not the markup. Crawlers revisit popular pages within days and low-traffic pages within weeks to months. Expect a quarter, not a week, and track server-log bot hits rather than trying to infer it from traffic.
If you want the full version of this audit as a single document — all seven checks expanded into a 100-point readiness list, plus the complete JSON-LD templates for Organization, SoftwareApplication, Article, Person, and FAQPage graphs, already wired with @id cross-references — I put it together here: * Structured for Answers → ***
Next in this series: How to Test If AI Crawlers Can Actually Read Your Site — the eight checks that tell you where you actually stand before you change a single line of markup.