{"id":15737,"date":"2026-09-06T11:22:43","date_gmt":"2026-09-06T09:22:43","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/toolbox\/live-json-ld-structured-data-validator\/"},"modified":"2026-09-06T11:22:43","modified_gmt":"2026-09-06T09:22:43","slug":"live-json-ld-structured-data-validator","status":"publish","type":"page","link":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/live-json-ld-structured-data-validator\/","title":{"rendered":"Live JSON-LD Structured Data Validator: what a page actually declares"},"content":{"rendered":"<div class=\"gtm-analyser-container\" style=\"background: var(--bg-panel, #1e1e24); padding: 25px; border-radius: 8px; border: 1px solid var(--border, #2a2a35);\">\n<p style=\"color: var(--text-secondary, #a0a0b0); margin-bottom: 20px;\">Structured data is a promise made in a language nobody reads by hand. A single missing comma turns the whole block into nothing; a relative image URL turns it into a promise that cannot be kept. This check pulls every ld+json block out of the served page and reads the nodes one by one, against the fields search engines expect for each type.<\/p>\n<div style=\"margin-bottom: 14px;\">\n        <label for=\"sd-url\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin-bottom: 5px;\">Page address<\/label><br \/>\n        <input id=\"sd-url\" type=\"text\" value=\"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/\" class=\"form-control\" style=\"width: 100%; padding: 10px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px; box-sizing: border-box; font-family: monospace;\">\n    <\/div>\n<p style=\"color: var(--text-secondary, #a0a0b0); font-size: 0.82rem; margin-bottom: 16px;\">From this server: exactly one request for the page, capped at 1.5 MB. Nothing is executed, no cookies are sent, nothing is stored beyond the rate counter.<\/p>\n<p>    <button id=\"sd-btn\" class=\"button\" style=\"background: var(--accent, #7ee787); color: var(--on-accent, #0b1114); border: none; padding: 12px 24px; border-radius: 6px; font-weight: 700; cursor: pointer;\">Check structured data<\/button><\/p>\n<div id=\"sd-ausgabe\" style=\"margin-top: 22px;\"><\/div>\n<p style=\"color: var(--text-secondary, #a0a0b0); font-size: 0.8rem; margin: 24px 0 0;\">Limits worth knowing: only JSON-LD in the served HTML is read. Microdata and RDFa are not \u2014 they sit scattered through the markup and would be a second tool. Blocks a script inserts later stay invisible, and required fields come from what search engines ask for today, which changes.<\/p>\n<\/div>\n<p><script>\n(function () {\n    'use strict';<\/p>\n<p>    const T = {\"einleitung\":\"Structured data is a promise made in a language nobody reads by hand. A single missing comma turns the whole block into nothing; a relative image URL turns it into a promise that cannot be kept. This check pulls every ld+json block out of the served page and reads the nodes one by one, against the fields search engines expect for each type.\",\"label_url\":\"Page address\",\"datenschutz\":\"From this server: exactly one request for the page, capped at 1.5 MB. Nothing is executed, no cookies are sent, nothing is stored beyond the rate counter.\",\"knopf\":\"Check structured data\",\"laeuft\":\"Fetching page...\",\"grenze\":\"Limits worth knowing: only JSON-LD in the served HTML is read. Microdata and RDFa are not \u2014 they sit scattered through the markup and would be a second tool. Blocks a script inserts later stay invisible, and required fields come from what search engines ask for today, which changes.\",\"h_knoten\":\"Nodes found\",\"tabelle_hinweis\":\"Nodes are counted after unpacking arrays and @graph, which is how a single block usually carries a whole set. Fields is how many keys the node has, a rough measure of how much it says.\",\"h_befunde\":\"Findings\",\"sp_nr\":\"No.\",\"sp_typ\":\"Type\",\"sp_name\":\"Name or headline\",\"sp_id\":\"@id\",\"sp_felder\":\"Fields\",\"zeile_seite\":\"Page\",\"zeile_bloecke\":\"ld+json blocks\",\"zeile_knoten\":\"Nodes\",\"zeile_dauer\":\"Took\",\"zeile_limit\":\"Checks left this hour\",\"wert_fehlt\":\"missing\",\"stufe_hoch\":\"High\",\"stufe_mittel\":\"Medium\",\"stufe_niedrig\":\"Low\",\"stufe_info\":\"Information\",\"stufe_gut\":\"In order\",\"keine_befunde\":\"Nothing to report.\",\"urteil_gut\":\"The structured data is sound.\",\"urteil_warnung\":\"It parses, but parts of it will be ignored.\",\"urteil_kritisch\":\"A block cannot be read, or a node has no type at all.\",\"fehler_kein_token\":\"The check could not be started because reCAPTCHA did not load.\",\"fehler_captcha\":\"reCAPTCHA classified the request as automated. Reloading the page normally helps.\",\"fehler_zu_viele\":\"The limit of {limit} checks per hour for this address has been reached.\",\"fehler_adresse\":\"That address cannot be used.\",\"fehler_abruf\":\"The page could not be fetched.\",\"fehler_zaehler\":\"The rate counter is unavailable, so nothing was checked.\",\"fehler_pruefdienst\":\"The reCAPTCHA service could not be reached.\",\"fehler_aufbau\":\"The service is not configured correctly. The fault is on this side.\",\"fehler_eingabe\":\"The request could not be read.\",\"fehler_methode\":\"Wrong request method.\",\"fehler_netz\":\"The service could not be reached.\",\"fehler_antwort\":\"The answer could not be read.\",\"fehler_unbekannt\":\"Something went wrong that has no message of its own.\",\"grund_leer\":\"Nothing was entered.\",\"grund_zu_lang\":\"The input is too long.\",\"grund_unlesbar\":\"It does not parse as an address.\",\"grund_schema\":\"Only http and https addresses are checked.\",\"grund_benutzerinfo\":\"Inputs with credentials in them are refused.\",\"grund_kein_punkt\":\"The host name needs at least one dot.\",\"grund_hostform\":\"A host name is expected, not an IP address.\",\"grund_port\":\"Only the ports 80, 443, 8080 and 8443 are checked.\",\"grund_gesperrter_bereich\":\"That host resolves into a private or reserved network. Those are never fetched.\",\"grund_kein_dns\":\"The host name does not resolve.\",\"grund_abruf\":\"The address did not answer.\",\"grund_zu_viele_spruenge\":\"The address redirects too often.\",\"befund_status\":\"The page answered with status {status} || Blocks were still read from whatever body came back.\",\"befund_seite_gekappt\":\"The page is larger than 1.5 MB || It was read up to that point; blocks beyond it were not seen.\",\"befund_ungueltiges_json\":\"Block {nr} is not valid JSON || {meldung}, {zeichen} characters. The entire block is discarded \u2014 not the faulty part, the whole thing. A trailing comma or a raw line break inside a string is enough.\",\"befund_kein_jsonld\":\"No ld+json block in the served HTML || Either the page carries no structured data, or a script adds it later. Search engines do render pages, but what is in the served HTML is what they see first and trust most.\",\"befund_keine_knoten\":\"The blocks contain no usable nodes || The JSON parses but holds nothing with a type \u2014 an empty object or an array of nothing.\",\"befund_bloecke\":\"{n} block(s) with {knoten} node(s) || A single block usually carries several nodes through @graph.\",\"befund_ohne_context\":\"Node {nr} ({typ}) carries no @context || Without it the vocabulary is undefined, and the node is read as arbitrary JSON rather than as schema.org.\",\"befund_fremder_context\":\"Node {nr} uses a context that is not schema.org || {context}. Valid JSON-LD, but search engines only act on the schema.org vocabulary.\",\"befund_ohne_type\":\"Node {nr} has no @type || Without a type there is nothing to interpret; the node is ignored entirely.\",\"befund_pflichtfeld_fehlt\":\"Node {nr} of type {typ} is missing {felder} || Those are the fields search engines expect for this type. Without them the node is read but produces no rich result.\",\"befund_typ_vollstaendig\":\"Node {nr} of type {typ} carries the expected fields || Nothing missing for this type.\",\"befund_typ_ohne_pflichtliste\":\"Node {nr} is of type {typ} || No required-field list is kept for this type here, so only the general checks apply.\",\"befund_adresse_relativ\":\"Node {nr}: {feld} is a relative address || {wert}. Structured data is read outside the page context; a relative URL has no base to resolve against and is dropped.\",\"befund_feld_leer\":\"Node {nr}: {feld} is empty || An empty field says less than an absent one: it looks like an answer and is none.\",\"befund_datum_unlesbar\":\"Node {nr}: {feld} is not a readable date || {wert}. Dates belong in ISO 8601 form; anything else is guesswork, and most parsers do not guess.\",\"befund_datum_ohne_iso\":\"Node {nr}: {feld} is readable but not ISO 8601 || {wert}. It works today because the parser is lenient. ISO form removes the question of which number is the month.\",\"befund_geaendert_vor_veroeffentlicht\":\"Node {nr}: dateModified lies before datePublished || One of the two is wrong. Search engines usually take the later one and may show it as the article date.\",\"befund_autor_als_text\":\"Node {nr}: author is a plain string || {wert}. A Person or Organization object with a name is what is expected; a bare string is accepted by some and ignored by others.\",\"befund_html_im_text\":\"Node {nr}: {feld} contains HTML || Structured data is plain text. Tags either show up literally or cause the field to be dropped.\",\"befund_headline_lang\":\"Node {nr}: headline is {n} characters || Long headlines are truncated in results. Around 110 characters is where that starts.\",\"befund_breadcrumb_ohne_position\":\"The breadcrumb list has {n} entries without position numbers || Order is what a breadcrumb is for. Without position the sequence is whatever the parser happens to read.\",\"befund_breadcrumb_luecke\":\"The breadcrumb positions have a gap || Found: {gefunden}. Positions must run 1, 2, 3 without holes; a gap makes the whole list unusable.\",\"befund_breadcrumb_ordentlich\":\"The breadcrumb list is complete with {n} entries || Positions run without gaps and every entry has a name.\",\"befund_breadcrumb_ohne_name\":\"{n} breadcrumb entries have no name || The entry exists but has nothing to display.\",\"befund_breadcrumb_ohne_item\":\"{n} breadcrumb entries have no item || Only the last entry may omit it \u2014 that one is the current page.\",\"befund_faq_ohne_antwort\":\"{n} of {gesamt} questions have no answer text || A question without acceptedAnswer text is dropped, and a FAQ block with dropped questions may be dropped entirely.\",\"befund_faq_vollstaendig\":\"All {n} questions carry an answer || The FAQ block is complete.\",\"befund_typ_mehrfach\":\"Type {typ} appears {n} times || For this type one node per page is expected. Two of them force search engines to choose, and the choice is theirs.\",\"befund_typen\":\"Types found: {liste} || That is what the page declares about itself.\",\"befund_viele_knoten\":\"More than {n} nodes || Only the first {n} were read; a page that declares that much usually repeats itself.\"};<\/p>\n<p>    var ENDPUNKT = '\/lw-sdcheck.php';\n    var SITEKEY = '6LcrPkEtAAAAAPo1QCOf-IIM2fCL0UfdJz4y2iSY';\n    var STUFEN = ['hoch', 'mittel', 'niedrig', 'info', 'gut'];<\/p>\n<p>    function liste(w) { return Array.isArray(w) ? w : []; }\n    function zahl(w) { return (typeof w === 'number' && isFinite(w)) ? w : null; }\n    function zeichen(w) { return (typeof w === 'string' && w !== '') ? w : null; }\n    function text(schluessel, daten) {\n        var t = T[schluessel];\n        if (typeof t !== 'string') { return null; }\n        return t.replace(\/\\{([a-z_0-9]+)\\}\/g, function (m, k) {\n            return (daten && daten[k] !== undefined && daten[k] !== null) ? String(daten[k]) : m;\n        });\n    }\n    \/** Adresse auf das kuerzen, was in einer Tabellenzelle lesbar bleibt. *\/\n    function kurz(url) {\n        var s = String(url || '');\n        s = s.replace(\/^https?:\\\/\\\/\/, '');\n        if (s.length <= 52) { return s; }\n        return s.slice(0, 24) + '\u2026' + s.slice(-26);\n    }\n\n    function bewerten(antwort) {\n        var a = antwort || {};\n        if (a.fehler) { return { fehler: String(a.fehler), grund: a.grund || null, limit: zahl(a.limit) }; }\n        var befunde = liste(a.befunde).map(function (f) {\n            return { key: String(f.key || ''), stufe: STUFEN.indexOf(f.stufe) === -1 ? 'info' : f.stufe, daten: (f.daten &#038;&#038; typeof f.daten === 'object') ? f.daten : {} };\n        });\n        var gruppen = {};\n        STUFEN.forEach(function (s) { gruppen[s] = befunde.filter(function (f) { return f.stufe === s; }); });\n        var knoten = liste(a.knoten).map(function (z) {\n            return { nr: zahl(z.nr), typ: zeichen(z.typ), name: zeichen(z.name), id: zeichen(z.id), felder: zahl(z.felder) };\n        });\n        return {\n            fehler: null, url: String(a.url || ''), endurl: String(a.endurl || ''),\n            urteil: (a.urteil === 'gut' || a.urteil === 'warnung' || a.urteil === 'kritisch') ? a.urteil : 'kritisch',\n            bloecke: zahl(a.bloecke), knoten: knoten,\n            befunde: befunde, gruppen: gruppen, dauer: zahl(a.dauer_ms), limitRest: zahl(a.limit_rest)\n        };\n    }\n\n    function skriptLaden() {\n        return new Promise(function (auf) {\n            if (window.grecaptcha) { auf(true); return; }\n            var s = document.createElement('script');\n            s.src = 'https:\/\/www.google.com\/recaptcha\/api.js?render=' + SITEKEY;\n            s.onload = function () { auf(true); }; s.onerror = function () { auf(false); };\n            document.head.appendChild(s);\n            setTimeout(function () { auf(!!window.grecaptcha); }, 8000);\n        });\n    }\n    function tokenHolen() {\n        return skriptLaden().then(function (da) {\n            if (!da || !window.grecaptcha || !window.grecaptcha.ready) { return null; }\n            return new Promise(function (auf) {\n                var fertig = false;\n                function einmal(w) { if (!fertig) { fertig = true; auf(w); } }\n                setTimeout(function () { einmal(null); }, 12000);\n                try {\n                    window.grecaptcha.ready(function () {\n                        if (fertig) { return; }\n                        if (!window.grecaptcha.execute) { einmal(null); return; }\n                        window.grecaptcha.execute(SITEKEY, { action: 'sdcheck' }).then(function (t) { einmal(t || null); }, function () { einmal(null); });\n                    });\n                } catch (e) { einmal(null); }\n            });\n        }, function () { return null; });\n    }\n    function abfragen(url) {\n        return tokenHolen().then(function (token) {\n            return fetch(ENDPUNKT, { method: 'POST', headers: { 'Content-Type': 'application\/json' }, body: JSON.stringify({ url: url, token: token || '' }) })\n                .then(function (r) { return r.json().then(function (j) { return j; }, function () { return { fehler: 'antwort' }; }); }, function () { return { fehler: 'netz' }; });\n        });\n    }\n\n    window.LW_TEST = window.LW_TEST || {};\n    window.LW_TEST.SD = { bewerten: bewerten, darstellen: null, text: text, kurz: kurz, ENDPUNKT: ENDPUNKT, STUFEN: STUFEN, T: T };\n\n    var btn = document.getElementById('sd-btn');\n    var out = document.getElementById('sd-ausgabe');\n    if (!btn || !out) { return; }\n\n    function el(tag, stil, txt) { var e = document.createElement(tag); if (stil) { e.setAttribute('style', stil); } if (txt !== undefined &#038;&#038; txt !== null) { e.textContent = txt; } return e; }\n    function wert(id) { var e = document.getElementById(id); return e ? e.value : ''; }\n    var UEBERSCHRIFT = 'font-family: \"Nunito Sans\", sans-serif; font-weight: 700; color: var(--text-primary, #e8e8ee); font-size: 0.95rem; margin: 22px 0 8px;';\n    var ZELLE = 'padding: 5px 12px 5px 0; color: var(--text-secondary, #a0a0b0); font-size: 0.87rem;';\n    var ZELLE_WERT = 'padding: 5px 12px 5px 0; color: var(--text-primary, #e8e8ee); font-size: 0.87rem; font-family: monospace; word-break: break-all;';\n    var KASTEN = 'background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); border-radius: 8px; padding: 14px 16px; margin: 0 0 10px;';\n    var GUT = ' color: #7ee787;', WARN = ' color: #ffa94d;', ROT = ' color: #ff7b72;', GRAU = ' color: #8a8a99;';\n    var FARBEN = { hoch: '#ff7b72', mittel: '#ffa94d', niedrig: '#e3b341', info: '#8a8a99', gut: '#7ee787' };\n    var URTEIL = { gut: GUT, warnung: WARN, kritisch: ROT };\n    function gitter(sp) { return el('div', 'display: grid; grid-template-columns: ' + sp + '; gap: 0 18px; align-items: baseline;'); }\n    function paar(g, n, w, stil) { g.appendChild(el('div', ZELLE, n)); g.appendChild(el('div', ZELLE_WERT + (stil || ''), w)); }\n\n    function tabelle(b) {\n        var huelle = el('div', 'overflow-x: auto; margin: 0 0 6px;');\n        var t = el('table', 'border-collapse: collapse; width: 100%; min-width: 560px; font-size: 0.84rem;');\n        var kopf = el('tr', '');\n        [T.sp_nr, T.sp_typ, T.sp_name, T.sp_id, T.sp_felder].forEach(function (n) {\n            kopf.appendChild(el('th', 'text-align: left; padding: 6px 12px 6px 0; color: #8a8a99; font-weight: 700; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.4px; border-bottom: 1px solid var(--border, #2a2a35); white-space: nowrap;', n));\n        });\n        t.appendChild(kopf);\n        b.knoten.forEach(function (z) {\n            var r = el('tr', '');\n            function zelle(txt, stil) { r.appendChild(el('td', 'padding: 7px 12px 7px 0; border-bottom: 1px solid var(--border, #2a2a35); font-family: monospace; color: var(--text-primary, #e8e8ee);' + (stil || ''), txt)); }\n            zelle(String(z.nr !== null ? z.nr : '-'), GRAU);\n            zelle(z.typ || T.wert_fehlt, z.typ ? GUT : ROT);\n            zelle(z.name ? (z.name.length > 46 ? z.name.slice(0, 45) + '\u2026' : z.name) : '-');\n            zelle(z.id ? kurz(z.id) : '-', GRAU);\n            zelle(String(z.felder !== null ? z.felder : '-'), GRAU);\n            t.appendChild(r);\n        });\n        huelle.appendChild(t);\n        return huelle;\n    }<\/p>\n<p>    function darstellen(b, ziel) {\n        ziel.innerHTML = '';\n        if (b.fehler) {\n            var txt = T['fehler_' + b.fehler] || T.fehler_unbekannt;\n            if (b.grund && T['grund_' + b.grund]) { txt = txt + ' ' + T['grund_' + b.grund]; }\n            if (b.limit !== null) { txt = txt.replace('{limit}', String(b.limit)); }\n            ziel.appendChild(el('p', ZELLE + WARN + ' margin: 0;', txt));\n            return;\n        }\n        ziel.appendChild(el('div', 'font-size: 1.05rem; font-weight: 700; margin: 0 0 12px;' + URTEIL[b.urteil], T['urteil_' + b.urteil]));<\/p>\n<p>        var g = gitter('auto auto');\n        paar(g, T.zeile_seite, b.endurl || b.url, GRAU);\n        paar(g, T.zeile_bloecke, String(b.bloecke !== null ? b.bloecke : '-'), b.bloecke ? GRAU : WARN);\n        paar(g, T.zeile_knoten, String(b.knoten.length), GRAU);\n        if (b.dauer !== null) { paar(g, T.zeile_dauer, b.dauer + ' ms', GRAU); }\n        if (b.limitRest !== null) { paar(g, T.zeile_limit, String(b.limitRest), GRAU); }\n        ziel.appendChild(g);<\/p>\n<p>        if (b.knoten.length) {\n            ziel.appendChild(el('div', UEBERSCHRIFT, T.h_knoten));\n            ziel.appendChild(tabelle(b));\n            ziel.appendChild(el('p', ZELLE + ' margin: 0 0 6px; font-size: 0.8rem;', T.tabelle_hinweis));\n        }<\/p>\n<p>        ziel.appendChild(el('div', UEBERSCHRIFT, T.h_befunde));\n        var irgendwas = false;\n        STUFEN.forEach(function (s) {\n            var gr = b.gruppen[s];\n            if (!gr.length) { return; }\n            irgendwas = true;\n            ziel.appendChild(el('div', 'font-weight: 700; font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.5px; margin: 14px 0 6px; color: ' + FARBEN[s] + ';', T['stufe_' + s] + ' (' + gr.length + ')'));\n            gr.forEach(function (f) {\n                var k = el('div', KASTEN + ' border-left: 3px solid ' + FARBEN[s] + ';');\n                var daten = {};\n                Object.keys(f.daten).forEach(function (n) { daten[n] = (n === 'url') ? kurz(f.daten[n]) : f.daten[n]; });\n                var t = text('befund_' + f.key, daten) || f.key;\n                var teile = t.split(' || ');\n                k.appendChild(el('div', 'color: var(--text-primary, #e8e8ee); font-size: 0.9rem; font-weight: 700;', teile[0]));\n                if (teile[1]) { k.appendChild(el('div', ZELLE + ' padding: 6px 0 0; line-height: 1.55;', teile[1])); }\n                ziel.appendChild(k);\n            });\n        });\n        if (!irgendwas) { ziel.appendChild(el('p', ZELLE + ' margin: 0;', T.keine_befunde)); }\n    }\n    window.LW_TEST.SD.darstellen = darstellen;<\/p>\n<p>    var laeuft = false;\n    btn.addEventListener('click', function () {\n        if (laeuft) { return; }\n        laeuft = true; btn.disabled = true;\n        out.innerHTML = '';\n        out.appendChild(el('p', ZELLE + GRAU + ' margin: 0;', T.laeuft));\n        abfragen(wert('sd-url')).then(function (a) { darstellen(bewerten(a), out); laeuft = false; btn.disabled = false; },\n            function () { darstellen(bewerten({ fehler: 'netz' }), out); laeuft = false; btn.disabled = false; });\n    });\n})();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Fetches a page, pulls out every ld+json block and reads the nodes one by one: does the JSON parse, does each node carry @context and @type, are the fields search engines expect present, are URLs absolute and dates machine-readable, and does a breadcrumb list hold together without gaps. One request, and only what the server sends.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":38,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"template-tool-base.php","meta":{"footnotes":""},"tags":[92735,91094,92757],"class_list":["post-15737","page","type-page","status-publish","hentry","tag-content","tag-seo","tag-web-development"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Live JSON-LD Structured Data Validator: what a page actually declares - Lukas Wojcik - Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/live-json-ld-structured-data-validator\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Live JSON-LD Structured Data Validator: what a page actually declares - Lukas Wojcik - Blog\" \/>\n<meta property=\"og:description\" content=\"Fetches a page, pulls out every ld+json block and reads the nodes one by one: does the JSON parse, does each node carry @context and @type, are the fields search engines expect present, are URLs absolute and dates machine-readable, and does a breadcrumb list hold together without gaps. One request, and only what the server sends.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/live-json-ld-structured-data-validator\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/live-json-ld-structured-data-validator\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/live-json-ld-structured-data-validator\\\/\",\"name\":\"Live JSON-LD Structured Data Validator: what a page actually declares - Lukas Wojcik - Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"datePublished\":\"2026-09-06T09:22:43+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/live-json-ld-structured-data-validator\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/live-json-ld-structured-data-validator\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/live-json-ld-structured-data-validator\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Toolbox\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Live JSON-LD Structured Data Validator: what a page actually declares\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"luky\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"luky\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Live JSON-LD Structured Data Validator: what a page actually declares - Lukas Wojcik - Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/live-json-ld-structured-data-validator\/","og_locale":"en_US","og_type":"article","og_title":"Live JSON-LD Structured Data Validator: what a page actually declares - Lukas Wojcik - Blog","og_description":"Fetches a page, pulls out every ld+json block and reads the nodes one by one: does the JSON parse, does each node carry @context and @type, are the fields search engines expect present, are URLs absolute and dates machine-readable, and does a breadcrumb list hold together without gaps. One request, and only what the server sends.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/live-json-ld-structured-data-validator\/","og_site_name":"Lukas Wojcik - Blog","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg","type":"image\/jpeg"}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"1 minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/live-json-ld-structured-data-validator\/","url":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/live-json-ld-structured-data-validator\/","name":"Live JSON-LD Structured Data Validator: what a page actually declares - Lukas Wojcik - Blog","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"datePublished":"2026-09-06T09:22:43+00:00","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/live-json-ld-structured-data-validator\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/live-json-ld-structured-data-validator\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/live-json-ld-structured-data-validator\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Toolbox","item":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/"},{"@type":"ListItem","position":3,"name":"Live JSON-LD Structured Data Validator: what a page actually declares"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"luky","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"luky"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/15737","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=15737"}],"version-history":[{"count":0,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/15737\/revisions"}],"up":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/38"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=15737"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=15737"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}