Why it matters
User or CMS content containing </script> ends the script element early; that breaks the JSON and is an XSS vector. The Next.js JSON-LD guide requires escaping <.
How to fix it
Serialize with JSON.stringify(data).replace(/</g, '\u003c') and use a native <script>, not next/script.
Example
// components/json-ld.tsx (Server Component). JSON.stringify doesn't escape "<", so a string containing
// </script> would break out of the tag; replace it with the JSON escape \u003c.
import type { Graph, Thing, WithContext } from 'schema-dts'
export function JsonLd({ data }: { data: WithContext<Thing> | Graph }) {
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(data).replace(/</g, '\\u003c') }}
/>
)
}References
More ai search rules
void geo reports 41 rules in this category. Generative-engine optimisation: whether AI crawlers that don't run JavaScript see the same content, valid and visible JSON-LD, an explicit AI robots policy, llms.txt, Markdown mirrors and answer-first writing.
hidden-streamed-contentCrawlers receive main content only inside hidden streaming containersai-bot-blockedAI crawler user agents get 401/403/429/503 or a challenge pageai-content-differsAI crawlers get materially different HTML than browsersjsonld-parse-errorJSON-LD block is not valid JSONjsonld-missingPage has no JSON-LDjsonld-not-in-rawJSON-LD is injected by JavaScripthome-entity-missingHome page lacks Organization + a single WebSite nodejsonld-schemaJSON-LD @context isn't schema.org or @type isn't a schema.org type