Skip to tool
FeuTex · free tools runs in-browser no bloat built by LiMiT

Schema Checker JSON (JSON-LD)

Paste your JSON-LD schema (or the full <script type="application/ld+json"> block) to validate JSON syntax, see common JSON-LD warnings, and quickly prettify or minify the markup. Runs locally (no network requests).

Category: SEO · URL: /tools/schema-checker-json.html

What this checks: valid JSON parsing, JSON-LD extraction from <script type="application/ld+json">, basic JSON-LD hints (missing @context/@type), and detected Schema.org types. No network calls.

Tip: If you paste a full HTML chunk, the tool will try to find and validate all JSON-LD script blocks.

Input (JSON-LD or full <script> block)
Ready
Limits: ~200KB input recommended (for speed).
Output
Privacy: runs locally in your browser. No uploads, no tracking scripts.

How to use

Use this tool to quickly validate and clean up Schema.org JSON-LD.

  1. Paste your JSON-LD (or the entire <script> block) into the input.
  2. Click Validate to see a short report and warnings.
  3. Click Prettify or Minify to generate formatted JSON output.
  4. Use Copy output to copy results.
Keywords this page targets (natural cluster): schema checker json, json-ld schema checker, json-ld validator offline, validate schema markup json, check json-ld syntax, extract json-ld from script tag, prettify json-ld, minify json-ld, schema.org json validator, find json parse error, list schema @type values, check @context schema.org, validate product schema json-ld, validate faq schema json-ld, validate breadcrumb schema json-ld, structured data json checker, json-ld linter, debug structured data json, schema json formatter
Secondary intents covered: Validate whether a JSON-LD snippet is valid JSON, Extract JSON-LD from HTML <script type="application/ld+json"> blocks, Identify missing or suspicious JSON-LD fields like @context and @type, List detected Schema.org types used in the markup, Prettify (format) JSON-LD for editing and review, Minify JSON-LD for embedding on a page, Spot multiple JSON-LD blocks and validate each one, Copy cleaned JSON output without sending data anywhere

FAQ

Does this validate Schema.org or only JSON syntax?

It guarantees valid JSON parsing and gives basic JSON-LD hints (like missing @context/@type), but it does not verify Rich Results eligibility.

Can I paste the whole <script type="application/ld+json"> block?

Yes. The tool extracts JSON-LD from <script type="application/ld+json">...</script> and validates each block it finds.

Will my data be uploaded anywhere?

No. The tool runs fully in your browser and does not make network requests.

Why does it say my JSON-LD is valid but still warns about @context or @type?

Valid JSON can still be incomplete for JSON-LD. Warnings highlight common requirements for Schema.org markup.

Can it fix JSON errors automatically?

It won’t guess fixes for broken JSON. Once your JSON parses, you can use Prettify/Minify to output clean JSON.

How do I handle multiple JSON-LD blocks on one page?

Paste the HTML containing them. The validator reports each block separately and can output a formatted bundle for review.

What’s the difference between JSON and JSON-LD?

JSON is the data format; JSON-LD is JSON with Linked Data conventions (like @context and @type) used for structured data.

\n","expected":"Blocks: 2"},{"name":"Missing @type warning","input":"{\"@context\":\"https://schema.org\",\"name\":\"No type\"}","expected":"Missing @type"}]; // The tool JS must attach: // - window.feutexReset(): resets UI // - window.feutexSelfTest(tests): returns string log (PASS/FAIL) // - window.feutexInit(): optional (function(){ const log = document.getElementById('selfTestLog'); const btn = document.getElementById('selfTestBtn'); const resetBtn = document.getElementById('resetBtn'); function setLog(txt){ if(log) log.textContent = txt || ''; } btn?.addEventListener('click', async () => { try { if(typeof window.feutexSelfTest !== 'function') { setLog('Self-test missing: window.feutexSelfTest not defined.'); return; } const out = await window.feutexSelfTest(FEUTEX_SELF_TESTS); setLog(out || 'No self-test output.'); } catch(e) { setLog('Self-test error: ' + (e?.message || e)); } }); resetBtn?.addEventListener('click', () => { try { if(typeof window.feutexReset === 'function') window.feutexReset(); setLog(''); } catch(e) { setLog('Reset error: ' + (e?.message || e)); } }); try { if(typeof window.feutexInit === 'function') window.feutexInit(); } catch(_e) {} document.getElementById('yr').textContent = String(new Date().getFullYear()); })(); \n', expected: 'Blocks: 2' }, { name: 'Missing @type warning', input: '{"@context":"https://schema.org","name":"No type"}', expected: 'Missing @type' } ]; function $(id) { return (typeof document !== 'undefined') ? document.getElementById(id) : null; } function setStatus(text) { const chip = $('statusChip'); if (chip) chip.textContent = text; } function showError(msg) { const el = $('toolError'); if (!el) return; if (msg && String(msg).trim()) { el.style.display = 'block'; el.textContent = String(msg); } else { el.style.display = 'none'; el.textContent = ''; } } function setOutput(text) { const out = $('toolOutput'); if (out) out.value = text || ''; } function getInput() { const inp = $('toolInput'); return inp ? inp.value : ''; } function normalizeJsonText(s) { if (s == null) return ''; let t = String(s).trim(); // Remove HTML comment wrappers sometimes used around JSON-LD if (t.startsWith('')) t = t.replace(/\s*-->$/, ''); return t.trim(); } function extractJsonLdBlocks(input) { const text = String(input || ''); const re = /]*type\s*=\s*(["'])application\/ld\+json\1[^>]*>([\s\S]*?)<\/script>/gi; const blocks = []; let m; while ((m = re.exec(text)) !== null) { blocks.push(normalizeJsonText(m[2])); if (blocks.length >= 50) break; // guard } if (blocks.length > 0) return blocks; return [normalizeJsonText(text)]; } function safeJsonParse(text) { const t = normalizeJsonText(text); if (!t) return { ok: false, error: 'Empty input.' }; try { const obj = JSON.parse(t); return { ok: true, value: obj }; } catch (e) { // Provide a small hint for common mistakes const hint = (t.includes("'") && !t.includes('"')) ? 'Hint: JSON requires double quotes (") for keys/strings.' : ''; return { ok: false, error: (e && e.message ? e.message : String(e)) + (hint ? ('\n' + hint) : '') }; } } function isObject(x) { return x && typeof x === 'object' && !Array.isArray(x); } function collectTypesAndContexts(root) { const types = new Set(); const contexts = new Set(); let hasGraph = false; const stack = [root]; let nodes = 0; const MAX_NODES = 20000; while (stack.length) { const node = stack.pop(); nodes++; if (nodes > MAX_NODES) break; if (Array.isArray(node)) { for (let i = 0; i < node.length; i++) stack.push(node[i]); continue; } if (!isObject(node)) continue; if (Object.prototype.hasOwnProperty.call(node, '@type')) { const t = node['@type']; if (Array.isArray(t)) { for (const it of t) if (typeof it === 'string') types.add(it); } else if (typeof t === 'string') { types.add(t); } } if (Object.prototype.hasOwnProperty.call(node, '@context')) { const c = node['@context']; if (typeof c === 'string') contexts.add(c); else if (Array.isArray(c)) { for (const it of c) if (typeof it === 'string') contexts.add(it); } else if (isObject(c)) { contexts.add('[object context]'); } } if (Object.prototype.hasOwnProperty.call(node, '@graph')) { hasGraph = true; } for (const k in node) { if (!Object.prototype.hasOwnProperty.call(node, k)) continue; const v = node[k]; if (v && typeof v === 'object') stack.push(v); } } return { types: Array.from(types).sort(), contexts: Array.from(contexts).sort(), hasGraph, nodeCount: nodes }; } function basicJsonLdWarnings(root) { const warnings = []; const top = root; const isArr = Array.isArray(top); const checkObj = (obj, label) => { if (!isObject(obj)) return; const hasContext = Object.prototype.hasOwnProperty.call(obj, '@context'); const hasType = Object.prototype.hasOwnProperty.call(obj, '@type'); const hasGraph = Object.prototype.hasOwnProperty.call(obj, '@graph'); if (!hasContext) warnings.push(`${label}: Missing @context (usually "https://schema.org").`); if (!hasType && !hasGraph) warnings.push(`${label}: Missing @type (or @graph).`); if (hasContext) { const c = obj['@context']; if (typeof c === 'string') { if (c === 'schema.org' || c === 'www.schema.org') warnings.push(`${label}: @context looks incomplete; use "https://schema.org".`); if (c.startsWith('http://schema.org')) warnings.push(`${label}: @context uses http; https is recommended.`); } } if (hasGraph) { const g = obj['@graph']; if (!Array.isArray(g)) warnings.push(`${label}: @graph should be an array.`); } }; if (isArr) { warnings.push('Top-level is an array. This is valid JSON, but ensure your platform supports an array JSON-LD block.'); for (let i = 0; i < Math.min(top.length, 5); i++) checkObj(top[i], `Item ${i + 1}`); } else { checkObj(top, 'Root'); } return warnings; } function formatJson(value, mode) { if (mode === 'minify') return JSON.stringify(value); return JSON.stringify(value, null, 2); } function validateAndBuildReport(rawInput, mode) { const input = String(rawInput || ''); // Size guard (soft) const size = new Blob([input]).size; const softWarnings = []; if (size > 250000) softWarnings.push(`Input is ~${Math.round(size / 1024)}KB. Large inputs may be slow on mobile.`); const blocksText = extractJsonLdBlocks(input).filter(b => b.trim().length > 0); const blocks = []; const errors = []; for (let i = 0; i < blocksText.length; i++) { const parsed = safeJsonParse(blocksText[i]); if (!parsed.ok) { errors.push(`Block ${i + 1}: ${parsed.error}`); blocks.push({ ok: false, error: parsed.error, raw: blocksText[i] }); } else { const analysis = collectTypesAndContexts(parsed.value); const warnings = basicJsonLdWarnings(parsed.value); blocks.push({ ok: true, value: parsed.value, analysis, warnings, raw: blocksText[i] }); } } const allOk = blocks.length > 0 && blocks.every(b => b.ok); if (mode === 'prettify' || mode === 'minify') { if (!allOk) { return { ok: false, report: `INVALID\nBlocks: ${blocks.length}\n\nFix JSON parsing errors before ${mode}.\n`, output: '' }; } if (blocks.length === 1) { return { ok: true, report: `VALID\nBlocks: 1\nMode: ${mode}`, output: formatJson(blocks[0].value, mode) }; } // Multi-block: output as a readable bundle let out = ''; for (let i = 0; i < blocks.length; i++) { out += `/* Block ${i + 1} */\n` + formatJson(blocks[i].value, mode) + '\n\n'; } out = out.trim(); return { ok: true, report: `VALID\nBlocks: ${blocks.length}\nMode: ${mode}\nNote: Output is a bundle; copy each block into its own