Audit Schema.org:
quando il validatore non basta

Misurare la differenza tra markup formalmente valido e markup ontologicamente corretto.

Perché "come scrivere JSON-LD corretto" non è la domanda giusta

Chi cerca "come scrivere JSON-LD" di solito arriva a una documentazione di proprietà, a un esempio copia-incollato, e a un validatore che restituisce esito positivo. Il problema è che il semaforo verde certifica la grammatica, non il significato. E il significato è esattamente ciò che Google e i motori AI leggono.

La differenza fondamentale è quindi cosa ci dice la Sintassi (il JSON è valido), la Semantica (il router collega le pagine) e l'Ontologia (il Knowledge Graph capisce cosa vendiamo).

Le relazioni dichiarate in Schema.org sono asserzioni su come è fatto il sito. Quando sono sbagliate — quando un hasPart dichiara un contenimento che non esiste, quando un breadcrumb vive dentro un Article invece che nella WebPage, quando un @id punta a un nodo che non è mai stato definito — nessuno strumento automatico di validazione sintattica lo segnala. Eppure il grafo che le macchine costruiscono contiene quegli errori.

SINTASSI "Il codice è scritto bene?"
→ Validatori automatici
SEMANTICA "Ha senso nel contesto?"
→ Audit umano
ONTOLOGIA "Descrive correttamente la realtà?"
→ Effetti sul Knowledge Graph

Da dove viene questo metodo

La metodologia dell'audit semantico non nasce da un'ipotesi teorica. Si è formata per accumulo: un errore alla volta, un template che generava lo stesso problema su centinaia di pagine, una correzione che rivelava il pattern successivo. Non c'è stata una fase iniziale in cui qualcuno ha "progettato" questa architettura: c'è stato un percorso di scoperta, e questo documento è la formalizzazione di quello che ha funzionato.

Da questa esperienza è derivata una convinzione precisa: i validatori controllano la grammatica, non il significato. Un hasPart verso una pagina esterna passa la validazione; un breadcrumb dentro un Article passa la validazione; un @id che punta a un nodo inesistente passa la validazione. Il semaforo verde dice "sintassi OK", non "ontologia coerente".

Quando il numero di pagine supera la capacità di controllarle una per una, gli errori non spariscono — cambiano forma, diventando pattern sistemici invece di refusi isolati. L'architettura, non la singola pagina, è ciò che va progettato con cura.

Cosa analizza un Audit Schema.org

L'audit non si limita a controllare se il codice è valido. Analizza il grafo nella sua interezza e verifica che regga dal punto di vista logico. Ecco le aree che controlla.

1. Coerenza dei tipi

Ogni @type è dichiarato una sola volta nel grafo, senza contraddizioni? Lo stesso @id non viene classificato in un punto come WebPage e in un altro come WebApplication? Questa è la Chimera Ontologica: il validatore non la segnala, ma l'AI che legge il grafo si blocca davanti a due tipi incompatibili sullo stesso nodo.

2. Risolvibilità degli @id

Ogni @id referenziato esiste davvero da qualche parte — nello stesso @graph o in una pagina raggiungibile? Questa analisi scova i Dangling Node: archi che puntano al nulla. Su una pagina è un dettaglio; su 250 pagine è un pattern che indebolisce l'intero grafo.

3. Appropriatezza delle proprietà

Il contenimento è dichiarato con hasPart solo quando è reale? I collegamenti tematici verso l'esterno usano significantLink? Il breadcrumb è nella WebPage o si è infiltrato dentro l'Article? Sono tutte scelte che passano il validatore ma cambiano il significato del grafo.

4. Parità dei dati

Ogni valore nel JSON-LD (rating, prezzo, claim) compare anche nel DOM visibile all'utente? Il markup nascosto è una violazione delle linee guida Google e può portare a un'azione manuale per markup ingannevole.

5. Separazione contenitore / contenuto

I loop di navigazione (menu, correlati, hub) puntano solo ai contenitori (#webpage) o anche ai contenuti finali (#article, #app)? Un loop che forza il tipo WebPage su un ID di software è un errore invisibile al validatore ma letale per il grafo.

6. Convenzione di naming dei frammenti

Ogni pagina rispetta una convenzione rigida per i frammenti (#webpage, #article, #breadcrumb, #organization)? Un audit efficace controlla che gli @id siano coerenti tra le pagine del sito, senza sorprese generate da template diversi.

7. Diagnostica dei conflitti di risoluzione

Quando un errore sembra non avere senso — perché due pagine strutturalmente identiche producono esiti diversi — la causa è nella risoluzione dei riferimenti, non nella pagina. Lo stesso @id che appare in più proprietà con range diversi, un array con elementi misti (tipizzati e non tipizzati), un frammento custom non riconosciuto: sono tutti meccanismi che generano errori downstream, apparentemente scorrelati dalla causa reale. Il capitolo Diagnostica copre il metodo per isolarli.

Le regole operative: come scrivere JSON-LD che regge il grafo

Diciannove pattern che ricorrono in produzione, con esempi di codice corretto e sbagliato. Ogni regola esiste perché un caso reale l'ha generata: un template che sbagliava su 250 pagine, un audit che ha rivelato un Dangling Node, un validatore che dava semaforo verde su una relazione ontologicamente rotta.

hasPart indica composizione letterale: X contiene fisicamente Y. significantLink indica rilevanza editoriale: Y è uno dei link più importanti della pagina, ma non è contenuto in X.

Test operativo: traduci la relazione in italiano ("X contiene fisicamente Y"). Se suona forzata, la proprietà corretta è significantLink.

significantLink accetta esclusivamente stringhe. Non Reference Node, non oggetti. Se passi {"@id": "..."} il validatore Schema.org dà errore bloccante.

// ❌ Errore validatore
"significantLink": [{ "@id": "https://sito.it/pagina/#article" }]

// ✅ Corretto
"significantLink": ["https://sito.it/pagina/#article"]

Critico: includi sempre il frammento finale (#article, #app, #webpage) nella stringa. La sintassi resta valida e l'AI sa esattamente a quale nodo stai puntando, evitando i Dangling Node.

3. Il breadcrumb: dove va davvero

Il breadcrumb appartiene alla WebPage, non all'Article. Il motivo è ontologico: il breadcrumb descrive un percorso di URL, e gli URL appartengono alle pagine, non ai contenuti. Molti siti lo mettono dentro l'Article e Google mostra comunque il percorso in SERP — da qui la falsa percezione che vada bene. Su scala diventa un pattern sistemico.

// ✅ Pattern corretto
{
  "@type": "WebPage",
  "@id": "/pagina/#webpage",
  "breadcrumb": { "@id": "/pagina/#breadcrumb" },
  "mainEntity": { "@id": "/pagina/#article" }
}

Regola architetturale: assegna il breadcrumb a livello di template di pagina, non di entità. In WordPress → single.php; in React → layout di pagina, non componente di contenuto.

4. Reference Node vs Stub Node

Quando referenzi un nodo definito altrove, usa solo @id. Aggiungere @type senza le proprietà essenziali (name, publisher, ecc.) crea un'entità parziale, che su larga scala genera ambiguità su quale sia la versione autorevole dell'entità.

// ❌ STUB — crea entità parziale
"hasPart": [
  { "@type": "WebPage", "@id": "/p1/#webpage", "url": "/p1/" }
]

// ✅ REFERENCE NODE — grafo appiattito
"hasPart": [
  { "@id": "https://sito.it/p1/#webpage" }
]

5. ItemList: quando generarlo e quando no

ItemList è un tipo, non una proprietà. Va generato solo quando la pagina è strutturalmente una lista: hub, indici di categoria, classifiche.

Ogni ListItem deve avere un name leggibile. Un URL nudo è segnale povero.

6. Formati dati misti: gestirli entrambi

Una proprietà può essere popolata in due forme valide. Il generatore deve riconoscerle entrambe.

// Formato A
["/pagina-a/", "/pagina-b/"]

// Formato B
[{ "id": "/pagina-a/", "type": "..." }]

Se il codice si aspetta un solo formato, funziona finché qualcuno — magari mesi dopo, magari un collaboratore diverso — scrive la lista nell'altro. Il markup smette silenziosamente di essere valido.

7. Conflitti di ID: il ponte sameAs

Se inietti un'Organization globale site-wide e una Organization ricca sulla pagina "Chi Siamo" con @id diverso, Google rischia di trattarle come due entità distinte. Non modificare il template globale: collega le due entità con sameAs.

{
  "@type": "Organization",
  "@id": "https://sito.it/#org-detail",
  "sameAs": "https://sito.it/#org"
}

8. La Chimera Ontologica

Un ID dichiarato come WebApplication in un punto del grafo e come WebPage in un altro è una contraddizione logica. Il validatore tace, l'AI si blocca davanti a due tipi incompatibili sullo stesso nodo. La causa più frequente: un loop di navigazione che forza @type: "WebPage" su ogni elemento, anche quando l'ID appartiene altrove a un software.

Regola: i loop di navigazione (menu, correlati, hub) devono puntare solo a contenitori (#webpage), mai a contenuti finali (#article, #app).

9. Target typing e rich snippet

@type: "WebApplication" è semanticamente corretto ma Google richiede la classe SoftwareApplication più operatingSystem per il rich result. Il tipo singolo non basta. Usa l'ereditarietà multipla.

"@type": ["SoftwareApplication", "WebApplication"],
"operatingSystem": "Web Browser"

Stesso pattern quando un vincolo di range blocca un link semanticamente valido:

// teaches si aspetta Text o DefinedTerm
"@type": ["WebApplication", "DefinedTerm"],
"@id": "/software/#app",
"name": "Protocollo SEO Avanzato"

10. Contenitore ≠ contenuto

Una pagina che ospita un tool non è il tool. Separa le entità con mainEntity.

// ❌
"@type": ["WebPage", "WebApplication"]

// ✅
{
  "@type": "WebPage",
  "@id": "/tool/#webpage",
  "mainEntity": {
    "@type": "WebApplication",
    "@id": "/tool/#app",
    "name": "Calcolatore SEO"
  }
}

Anti-pattern: applicare WebPage o Article indiscriminatamente in un header condiviso. Correggi con routing semantico — il tipo dipende dai dati, non solo dal layout.

11. about vs mentions

Troppi about diluiscono il segnale: la pagina compete per query sbagliate.

12. Parità dei dati

Ogni valore nel JSON-LD deve essere visibile nel DOM renderizzato. Se dichiari aggregateRating: 4.8 e nel DOM non c'è un badge con "4.8", stai violando le linee guida Google. Rischio: azione manuale per markup ingannevole.

13. Convenzione di naming dei frammenti

Adotta una convenzione rigida e verificala periodicamente. Esempio:

I validatori non aprono gli URL: non verificano che l'@id esista davvero dall'altra parte. Un Fragment Audit — estrarre tutti gli @id usati nei loop di navigazione e verificare che puntino ai contenitori — è l'unico modo per scovarli.

14. hasPart + ItemList: la trappola dell'indice

Non inserire un ItemList dentro hasPart. ItemList è classificato come Intangible (struttura dati astratta), non come CreativeWork. Un libro ha capitoli, non "una lista di dati".

// ❌
"hasPart": { "@type": "ItemList", "itemListElement": [...] }

// ✅
"hasPart": [
  { "@id": "https://sito.it/capitolo-1/#webpage" },
  { "@id": "https://sito.it/capitolo-2/#webpage" }
]

15. Il pattern bidirezionale CollectionPage

Su un vero Topic Cluster — Pillar Page che organizza una serie di approfondimenti — la bidirezionalità è preziosa:

16. Global identifiers: citare terze parti

Se citi un software terzo (isBasedOn: SoftwareApplication), Google attiva i filtri rich-snippet commerciali e ti inonda di warning per offers e operatingSystem mancanti. La soluzione pigra è declassare a Thing — che lobotomizza il grafo. La soluzione corretta è puntare a un IRI globale.

"isBasedOn": {
  "@type": "SoftwareApplication",
  "@id": "https://www.wikidata.org/wiki/Q161676",
  "name": "WordPress"
}

Il bot riconosce una citazione esterna, non una distribuzione locale: i filtri commerciali si disinnescano, il @type resta preservato.

17. Conflitto @id cross-proprietà

Quando lo stesso @id appare in più proprietà con range diversi all'interno dello stesso grafo, e non è definito localmente con un @type esplicito, il validatore lo risolve una sola volta — alla prima occorrenza — e propaga il tipo risultante a tutte le altre. Se il tipo risolto è debole (Thing), il declassamento può invalidare proprietà che richiedono range più restrittivi come CreativeWork.

// ❌ Conflitto: stesso @id in hasPart (richiede CreativeWork)
// e in isRelatedTo (range libero), senza @type locale

{
  "@graph": [
    {
      "@type": "CollectionPage",
      "hasPart": [
        { "@id": "https://sito.it/pagina/#article" }
      ]
    },
    {
      "@type": "Service",
      "isRelatedTo": [
        { "@id": "https://sito.it/pagina/#article" }
      ]
    }
  ]
}

// ✅ Soluzione: differenziare i frammenti
// hasPart punta al contenuto (#article)
// isRelatedTo punta al contenitore (#webpage)

{
  "@graph": [
    {
      "@type": "CollectionPage",
      "hasPart": [
        { "@id": "https://sito.it/pagina/#article" }
      ]
    },
    {
      "@type": "Service",
      "isRelatedTo": [
        { "@id": "https://sito.it/pagina/#webpage" }
      ]
    }
  ]
}

Il segnale diagnostico non è il messaggio d'errore, che appare downstream in un punto apparentemente non correlato. È la presenza dello stesso @id in più proprietà. Quando trovi quel pattern, cerca lì la causa prima di guardare altrove.

18. Auto-inferenza da frammento: la dipendenza fragile

I Reference Node puri ({"@id": "..."}) funzionano solo se il validatore riesce a risolvere l'@id. Esistono tre livelli di risoluzione, in ordine di priorità:

  1. Definizione locale: l'@id esiste nel @graph della pagina corrente come oggetto con @type esplicito. Risoluzione garantita.
  2. Auto-inferenza dal frammento: se il frammento è in whitelist di convenzioni note (#webpage → WebPage, #article → Article, #faq → FAQPage, #breadcrumb → BreadcrumbList), il validatore inferisce il tipo.
  3. Declassamento a Thing: se il frammento è custom e non c'è definizione locale, il tipo è Thing. Questo può invalidare proprietà con range più restrittivi.

Conseguenza pratica: i Reference Node puri funzionano "per fortuna" quando usano frammenti standard. Basta un frammento custom in un punto del grafo e il meccanismo si rompe silenziosamente. Un audit efficace verifica che ogni @id referenziato sia in whitelist o definito esplicitamente nel grafo locale.

19. Indice come vista, non contenitore

Una pagina che elenca altre pagine non le contiene. Sono due relazioni ontologicamente diverse:

La tentazione di usare hasPart su un indice è forte ("l'indice contiene i capitoli"). È ontologicamente sbagliato: i capitoli sono parte del libro, non dell'indice che li elenca.

// ❌ Indice con hasPart verso i capitoli
{
  "@type": "CollectionPage",
  "@id": "/indice/#webpage",
  "hasPart": [
    { "@id": "/capitolo-1/#webpage" },
    { "@id": "/capitolo-2/#webpage" }
  ]
}

// ✅ Indice con significantLink (stringhe) verso i capitoli
{
  "@type": "CollectionPage",
  "@id": "/indice/#webpage",
  "significantLink": [
    "https://sito.it/capitolo-1/#webpage",
    "https://sito.it/capitolo-2/#webpage"
  ]
}

Il contenimento resta sul contenitore reale (il libro, l'opera, la raccolta). L'indice è una vista che espone l'elenco, non un contenitore fisico.

Conseguenza sui pattern narrativi: in un contenuto a bivi (percorso interattivo, tutorial a step, albero di scelte), ogni nodo appartiene al nodo precedente con isPartOf, e i nodi successivi si dichiarano con significantLink. L'indice resta la vista d'insieme con significantLink verso tutti i nodi. Nessun hasPart.

Diagnostica: quando due strutture identiche danno esiti diversi

C'è un momento, in ogni audit, in cui due pagine apparentemente identiche ottengono risultati opposti dal validatore. Una passa, l'altra no. Il codice sembra lo stesso. La reazione istintiva è pensare a un errore del validatore, a una cache, a un problema temporaneo.

Non è niente di tutto questo. Il motivo è che i validatori risolvono i riferimenti in modo contestuale, non isolato: dipende da cosa c'è nel resto del grafo, non solo da quello che scrivi nel punto specifico.

Il principio: risoluzione una volta sola, propagazione

Quando un validatore incontra un riferimento a un @id, lo risolve una sola volta — alla prima occorrenza — e usa il risultato per tutte le occorrenze successive. La decisione non viene rivalutata per ogni proprietà.

Se la prima occorrenza è in un contesto che non permette di determinare il tipo (perché l'@id non è definito localmente e il frammento non è riconoscibile), il validatore lo classifica come Thing. Quel Thing viene poi propagato anche alle altre proprietà che referenziano lo stesso @id.

Se una di quelle proprietà richiede un range più specifico (hasPart richiede CreativeWork, per esempio), il Thing non è compatibile e il validatore segnala l'errore sulla proprietà sbagliata — apparentemente scorrelata dalla causa reale.

Il pattern sospetto: stesso @id in più proprietà

Il segnale diagnostico più importante non è il messaggio d'errore, è la presenza dello stesso @id in più di una proprietà all'interno dello stesso grafo.

Quando trovi questo pattern, controlla due cose:

  • L'@id è definito localmente con un @type esplicito? Se sì, nessun problema: la risoluzione è garantita e non c'è declassamento.
  • Le proprietà che lo usano hanno range compatibili? Se una è hasPart (range ristretto) e l'altra è una proprietà generica, il range più restrittivo richiede un tipo più forte del Thing.

Se l'@id non è definito localmente e le proprietà hanno range incompatibili, hai trovato la causa. Differenzia i frammenti: una proprietà punta al contenuto (#article), l'altra al contenitore (#webpage). Sono due entità diverse per natura, e il conflitto si risolve senza toccare il tipo dell'articolo.

Incoerenza interna agli array

Un caso correlato e subdolo: un array (hasPart, mentions, isRelatedTo) in cui alcuni elementi hanno @type esplicito e altri no. Il validatore cerca coerenza interna, e in assenza di essa:

  • Può declassare gli elementi tipizzati al tipo più debole degli altri
  • Può segnalare errori sugli elementi non tipizzati anche se il problema è l'uniformità
  • Il messaggio d'errore può non nominare l'elemento effettivamente problematico

Regola operativa: in un array, gli elementi devono essere tutti tipizzati o tutti senza @type. Mai misti. Un array misto è un array che nasconde problemi.

Padre URL vs padre semantico

Due concetti diversi che vengono spesso confusi, e che i validatori non distinguono.

Il padre URL è fisico: si ottiene tagliando l'ultimo segmento dell'URL. Ogni rotta ne ha uno, che esista o no come pagina pubblica.

Il padre semantico è quello dichiarato in isPartOf. Non sempre coincide con il padre URL, e non deve.

Esempi tipici di scostamento intenzionale:

  • Una pagina di servizio può essere figlia strutturale di un minihub e correlata tematicamente (via about) a una pagina enciclopedica
  • Un volume può appartenere alla sua serie, non alla pagina indice dei volumi
  • Un tool può essere figlio di un centro strumenti invece che della sua categoria URL
  • Una pagina di primo livello può riferirsi alla home, anche se il suo padre URL "naturale" sarebbe un prefisso che non è una pagina pubblica

Il test diagnostico: confronta URL padre fisico e isPartOf dichiarato. Gli scostamenti non sono automaticamente errori. Sono scelte. Ma vanno verificate una per una e classificate in due categorie: scelte deliberate e errori probabili.

Metodo di verifica in quattro passi

Passo 1 — Cattura del grafo locale

Estrai il JSON-LD della pagina problematica. Individua tutte le entità con @type esplicito e tutti i riferimenti @id senza definizione locale.

Passo 2 — Mappatura dei conflitti

Costruisci una mappa @id → [proprietà che lo usano]. Identifica gli @id che appaiono in più di una proprietà.

Passo 3 — Risoluzione dei conflitti

Per ogni @id in conflitto: è definito localmente con @type? Se no, il frammento è in whitelist di convenzioni note? Se nemmeno, differenzia i frammenti tra le proprietà, o aggiungi una definizione esplicita.

Passo 4 — Verifica dell'auto-inferenza

Per ogni @id referenziato ma non definito localmente, verifica che il frammento sia in whitelist. Se non lo è, aggiungi definizione esplicita o cambia frammento.

Caso pratico (generico)

Due pagine con struttura praticamente identica:

  • Entrambe figlie della stessa pagina madre
  • Entrambe referenziate in hasPart della madre
  • Entrambe con entità propria di tipo TechArticle
  • Entrambe senza @type nel riferimento

Una passa il validatore, l'altra no. Nessuna differenza apparente nel codice delle due pagine.

Diagnosi: la pagina che fallisce è referenziata anche da un'altra proprietà — per esempio isRelatedTo di un Service — con lo stesso @id. Il validatore ha risolto quel @id alla prima occorrenza (in isRelatedTo) e l'ha classificato come Thing perché non definito localmente, poi ha propagato il Thing a tutte le altre occorrenze — inclusa quella in hasPart, che richiede un range CreativeWork e rifiuta Thing.

Soluzione: differenziare i due riferimenti. hasPart verso l'articolo (#article), isRelatedTo verso la pagina (#webpage). Le due entità sono diverse per natura — contenuto vs contenitore — e il conflitto si risolve senza toccare il tipo dell'articolo.

Lezione: quando un riferimento è ambiguo, il validatore non segnala l'ambiguità: segnala l'errore downstream, in un punto che può sembrare non correlato. Il segnale utile è la presenza dello stesso @id in più proprietà. È quel pattern che va cercato per primo quando un errore "non ha senso".

Mappa sintomo → regola

Per chi arriva con un problema già identificato, questa tabella fa da indice rapido.

SintomoRegola
Validatore verde, rich snippet assente§9 Target typing
"Elemento senza nome" su entità annidata§4 Reference Node
Breadcrumb in SERP ma grafo incoerente§3 WebPage
Dangling node, @id orfano§1, §13
Due organizations nel Knowledge Graph§7 sameAs
FAQ trattate come lista link§5 scope
Tipo sbagliato forzato da loop§8 Chimera
JSON-LD enorme che rallenta la pagina§4 grafo appiattito
ItemList su prodotto singolo§5 scope
Errore validatore su significantLink§2 solo stringa
Due pagine identiche con esiti diversi dal validatore§17, Diagnostica
Errore su proprietà apparentemente scorrelataDiagnostica, Passo 2
Errore Thing su una proprietà con range ristretto§17
Indice con hasPart verso le sue voci§19
Reference Node che funziona su una pagina e non su un'altra§18

In caso di dubbio

Traduci la tripla JSON-LD in una frase semplice (Soggetto → Verbo → Oggetto). Se la frase suona forzata, la proprietà è sbagliata — indipendentemente da cosa dice il validatore.

"Questo Article contiene fisicamente un Breadcrumb" → forzato → il breadcrumb appartiene alla WebPage.

"Questa WebPage contiene quest'altra WebPage esterna" → forzato → usa significantLink.

"Questa WebPage è una WebApplication" → sbagliato → usa mainEntity.

"Questo indice contiene fisicamente i suoi capitoli" → forzato → l'indice elenca, il libro contiene.

Regola finale: ogni regola sopra esiste perché un validatore ha detto "OK" mentre il Knowledge Graph diceva "no". Fidati del grafo, non della spunta verde.

La checklist operativa

Domande concrete che un Audit Semantico pone a ogni pagina. Non è un test da spuntare una volta: è una griglia da riapplicare quando si aggiunge un tipo di contenuto o si automatizza una regola.

Sul singolo documento

Sull'intero sito

Cosa un Audit non può fare

Per essere utile, un metodo deve dichiarare anche i propri limiti.

A chi serve (e a chi no)

Serve davvero a piattaforme editoriali con decine o centinaia di pagine correlate, e-commerce con catalogo strutturato, architetture a topic cluster, siti con template automatici che generano markup a scala, progetti che devono essere letti da AI.

È overkill per siti vetrina da 5-10 pagine statiche, progetti gestiti da plugin standard (Yoast, RankMath) che coprono già Organization, WebSite, WebPage, blog monografici con un solo tipo di contenuto. Su questi progetti, un audit completo è un investimento sproporzionato: il plugin è sufficiente, e la parte ontologica diventa un esercizio teorico senza impatto pratico.

Approfondimenti: teoria & pratica

Questa pagina presenta il metodo dell'audit. Le due guide collegate lo approfondiscono da due angolazioni complementari, sul sito madre IMWEB.

📘 La teoria — Dati Strutturati Avanzati La guida di riferimento sul vocabolario: isPartOf, hasPart, significantLink, ItemList, about, mentions. Spiega il significato ontologico di ogni proprietà, le regole del polimorfismo e del target typing, la parità dei dati, il caso studio sui falsi positivi. Vai alla guida teorica → 📗 La pratica — Architettura Semantica su Scala Il seguito pratico: cosa succede quando i pattern corretti teoricamente vengono replicati da un template su centinaia di pagine. Sei "crepe" reali incontrate in produzione, sei trappole dei motori di rendering, un framework di debugging in 4 step (con il Fragment Audit) e un'architettura di separazione dei dati. Vai alla guida pratica →

Le due guide sono complementari e si rimandano a vicenda. La teoria senza la pratica resta un esercizio intellettuale; la pratica senza la teoria diventa una checklist di regole senza il perché.

FAQ

Basta seguire le specifiche di Schema.org per scrivere JSON-LD corretto?

Seguire le specifiche è la condizione necessaria, non sufficiente. Le specifiche ti dicono quali tipi esistono, quali proprietà accettano, quali range sono validi. Non ti dicono se la relazione che stai dichiarando ha senso per il tuo sito. Un hasPart verso una pagina esterna è sintatticamente valido, ma ontologicamente discutibile. Il validatore passa, il grafo no.

Un audit Schema.org sostituisce il Rich Results Test di Google?

No, lo completa. Il Rich Results Test verifica la compatibilità con i rich snippet di Google: ti dice se il markup è valido secondo gli standard di Search Console e se verrà mostrato un rich result. L'audit semantico verifica un livello diverso: che le relazioni dichiarate siano coerenti, che i nodi siano risolvibili, che il grafo regga. Puoi avere un rich result perfetto e un grafo incoerente — e viceversa.

Cosa sono i Dangling Node e perché un audit dovrebbe scovarli?

Un Dangling Node è un riferimento @id che punta a un'entità che non esiste nel grafo. In teoria dei grafi, un arco che punta al nulla riduce la coerenza del dataset. In pratica, quando un sistema AI costruisce il Knowledge Graph del tuo sito, trova un rimando a un'entità che non riesce a risolvere, e deve indovinare o ignorarlo. Ripetuto su centinaia di pagine, indebolisce la chiarezza del grafo.

Perché due pagine con struttura identica ottengono esiti diversi dal validatore?

Perché il validatore risolve i riferimenti @id in modo contestuale, non isolato. Se lo stesso @id appare in più proprietà con range diversi e non è definito localmente, il validatore lo risolve una volta sola — alla prima occorrenza — e propaga il tipo risultante. Se il tipo è debole (Thing), il declassamento può invalidare proprietà che richiedono range più restrittivi come CreativeWork. Il sintomo appare downstream, in un punto che sembra non correlato.

Ogni quanto va rifatto un Audit Semantico?

Ogni volta che cambia una di queste tre cose: le specifiche Schema.org, le linee guida Google sui rich result, o la struttura del sito. In pratica: un audit completo ogni volta che si aggiunge un nuovo tipo di contenuto, si modifica un template che genera markup, o si aggiunge una nuova sezione al sito. Non è un certificato a vita — è una fotografia dello stato del grafo, va rinnovata.

Serve un audit se uso già un plugin SEO che genera JSON-LD?

Dipende. Un plugin standard genera markup corretto per i casi comuni: Organization, WebSite, WebPage, Article, breadcrumb. Copre la sintassi per la maggior parte delle pagine di un sito normale. Ma non conosce la struttura specifica del sito: non sa quali pagine sono hub, quali sono contenuto singolo, come si collegano tra loro. Su un piccolo sito vetrina, il plugin basta. Su un progetto a topic cluster o un catalogo, serve un audit sopra il plugin.

🔬 OLTRE IL VALIDATORE

Vuoi verificare il tuo JSON-LD
oltre la sintassi?

Se gestisci un sito con più di qualche decina di pagine, la domanda non è "il mio markup è valido". La domanda è: "il mio grafo reggerà quando il sito crescerà?"

Avvia l'Audit 360° → Leggi la teoria

Usiamo cookie tecnici necessari al funzionamento del sito. Nessun dato personale viene raccolto e ceduto a terzi per finalità pubblicitarie. Leggi l'informativa privacy.