) within string values — use backslash-forward-slash."}} ]}, {"@type":"BreadcrumbList","itemListElement":[ {"@type":"ListItem","position":1,"name":"Home","item":"https://aiwebpageseo.com/seo-audit-platform.html"}, {"@type":"ListItem","position":2,"name":"Learning Hub","item":"https://aiwebpageseo.com/learning-hub.html"}, {"@type":"ListItem","position":3,"name":"JSON Checker Fixes","item":"https://aiwebpageseo.com/aipageseo-demo-pages/json-checker-fixes-index.html"}, {"@type":"ListItem","position":4,"name":"Fix JSON-LD Syntax","item":"https://aiwebpageseo.com/aipageseo-demo-pages/how-to-fix-json-syntax.html"} ]} ]}
JSON-LD syntax errors mean Google, Bing and every other crawler ignores your structured data entirely. One unescaped quote in a product description breaks the whole schema block — no rich snippet, no knowledge graph, no anything. Most syntax errors come from template engines interpolating user content without escaping. The fix is build JSON-LD as real objects, serialise with JSON.stringify, and validate at build time.
</script> within a string value<!-- BROKEN: title contains double quote -->
<script type="application/ld+json">
{
"@type": "Article",
"headline": "Apple's "iPhone" announcement"
}
</script>
<!-- FIXED: escape inner quotes -->
<script type="application/ld+json">
{
"@type": "Article",
"headline": "Apple's \"iPhone\" announcement"
}
</script>
Or better — use a typographic quote which doesn't need escaping:
"headline": "Apple's “iPhone” announcement"
If a string value contains </script>, the browser thinks the JSON-LD block ended — the rest of your JSON gets treated as HTML and breaks.
<!-- BROKEN -->
<script type="application/ld+json">
{
"description": "Read about </script> tag use in HTML"
}
</script>
<!-- FIXED — escape the forward slash -->
<script type="application/ld+json">
{
"description": "Read about <\/script> tag use in HTML"
}
</script>
JSON.stringify doesn't escape forward slashes by default. Add post-processing:
JSON.stringify(data).replace(/<\/script/gi, '<\\/script')
Most syntax errors disappear when you stop hand-writing JSON-LD in templates.
<!-- Liquid template — fragile -->
<script type="application/ld+json">
{
"@type": "Product",
"name": "{{ product.title }}",
"description": "{{ product.description }}"
}
</script>
<!-- If product.title contains a quote, this breaks -->
<!-- Build the object in code, serialise once -->
<script type="application/ld+json">
{{ product_schema | json }}
</script>
# In your controller / data layer:
product_schema = {
'@context': 'https://schema.org',
'@type': 'Product',
'name': product.title,
'description': product.description
}
The | json filter (Jekyll), {!! json_encode($data) !!} (Laravel), JSON.stringify(data) (Node), json.dumps(data) (Python) — each properly escapes quotes, newlines, special characters.
function ProductPage({ product }) {
const schema = {
'@context': 'https://schema.org',
'@type': 'Product',
name: product.title,
description: product.description,
image: product.images[0],
offers: {
'@type': 'Offer',
price: product.price,
priceCurrency: 'USD',
availability: product.inStock
? 'https://schema.org/InStock'
: 'https://schema.org/OutOfStock'
}
};
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(schema).replace(/<\/script/g, '<\\/script')
}}
/>
<ProductContent product={product} />
</>
);
}
Catch invalid JSON-LD in CI before it ships.
# scripts/validate-json-ld.js
const fs = require('fs');
const path = require('path');
const cheerio = require('cheerio');
const errors = [];
const htmlFiles = require('glob').sync('dist/**/*.html');
for (const file of htmlFiles) {
const $ = cheerio.load(fs.readFileSync(file, 'utf8'));
$('script[type="application/ld+json"]').each((i, el) => {
try {
JSON.parse($(el).html());
} catch (e) {
errors.push(`${file}: ${e.message}`);
}
});
}
if (errors.length) {
console.error('Invalid JSON-LD found:');
errors.forEach(e => console.error(' ', e));
process.exit(1);
}
console.log('All JSON-LD valid');
| Error | Cause | Fix |
|---|---|---|
Unexpected token " | Unescaped quote in string | Use JSON.stringify, not concat |
Unexpected token , | Trailing comma after last property | Remove trailing commas |
Unexpected end | Missing closing brace/bracket | Match every open with close |
Unexpected token ' | Single quotes used | Replace with double quotes |
Bad control character | Raw newline in string | Use \n escape sequence |