Tutorial: JSON-LD, który wyszukiwarki naprawdę czytają
Spis treści
Dane strukturalne nie mają stanu błędu, który ktokolwiek by zauważył. Strona ze względną ścieżką obrazu, datą w zapisie lokalnym albo ceną z symbolem waluty jest serwowana dokładnie tak samo jak poprawna, plasuje się dokładnie tak samo jak poprawna i po prostu nigdy nie dostaje wyniku rozszerzonego, dla którego ją napisano. Znaczniki są, crawler je czyta i nic się nie dzieje.
To czyni z danych strukturalnych raczej problem utrzymania niż pisania. Błędy są mechaniczne, powtarzają się na każdej stronie powstałej z tego samego szablonu, a jeden niewłaściwy znak w polu, którego żaden odwiedzający nigdy nie widzi, rozstrzyga, czy wpis pokaże ocenę, czy goły niebieski odnośnik. Poniżej opisany jest łańcuch, przez który musi przejść fragment znaczników, oraz cztery miejsca, w których zwykle z niego wypada.

Dwa wiersze, na których wszystko się opiera
Zanim odczytana zostanie choćby jedna właściwość, dwa pola rozstrzygają, czy blok w ogóle zostanie obejrzany. @context musi wskazywać na https://schema.org; bez tego obiekt jest kawałkiem JSON bez słownika, a każda właściwość w nim nic nie znaczy. @type nazywa następnie opisywaną rzecz. Zapis ma przy tym znaczenie: Article jest typem, article nim nie jest, i różnica ta nigdzie nie wywołuje ostrzeżenia.
Tam, gdzie do jednej strony należy kilka obiektów – artykuł, jego autor i ścieżka okruszków – mogą stać w jednym bloku pod @graph albo w osobnych elementach skryptu. Oba sposoby działają. Nie działają natomiast dwa bloki opisujące tę samą rzecz odmiennie, ponieważ parser nie ma reguły rozstrzygającej, o który z nich chodzi.
Cztery błędy, które nie dają komunikatu
Na te cztery przypada większość znaczników, które są poprawne, a mimo to nic nie pokazują. Łączy je jedna cecha: dane pole jest dla odwiedzających niewidoczne, więc nikt nie zauważa, że jest błędne.
| Zapisane tak | Co się dzieje | Jak być powinno |
|---|---|---|
"image": "/img/a.jpg" |
Ścieżka nigdy nie zostaje rozwiązana, obraz uchodzi za brakujący, a wraz z nim znika najbardziej widoczna część wyniku. | Pełny adres wraz ze schematem. |
"datePublished": "26.08.2026" |
Pole zostaje pominięte. Artykuł bez daty publikacji traci datę we wpisie. | ISO 8601: 2026-08-26 albo z godziną i przesunięciem. |
"price": "49,90 EUR" |
Oferta zostaje odrzucona w całości – cena i dostępność znikają razem. | Sama liczba z kropką, waluta w priceCurrency. |
"@type": "article" |
Typ jest nieznany, każda właściwość poniżej zostaje odczytana jako rzecz nieokreślona. | Dokładnie Article, z wielką literą włącznie. |
Pierwsze trzy pochodzą z szablonów, które wypełniają znaczniki tymi samymi zmiennymi co samą stronę: ścieżka obrazu jest względna, bo szablon zapisuje ścieżki względne, data jest sformatowana, bo sformatowana data i tak była pod ręką, a cena niesie swoją walutę, bo tak się ją drukuje. Dane strukturalne potrzebują wartości surowych, a nie przygotowanych do wyświetlenia.
Article: jedno pole obowiązkowe i cztery, które mają znaczenie
Artykuł potrzebuje pola headline i niczego więcej. Wszystko, co sprawia, że wynik wygląda jak wynik, jest dobrowolne – i właśnie dlatego tak wiele znaczników przechodzi kontrolę i nic nie pokazuje.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "JSON-LD, który wyszukiwarki naprawdę czytają",
"description": "Dlaczego dane strukturalne zawodzą bez komunikatu o błędzie.",
"image": ["https://www.example.com/images/json-ld.png"],
"author": { "@type": "Person", "name": "Lukas Wojcik" },
"datePublished": "2026-08-26",
"dateModified": "2026-08-26",
"mainEntityOfPage": { "@type": "WebPage", "@id": "https://www.example.com/blog/json-ld/" }
}
</script>
Cztery drobiazgi rozstrzygają, czy te znaczniki cokolwiek przyniosą. Pole headline zostaje ucięte powyżej mniej więcej 110 znaków, więc tytuł złożony z tytułu strony i nazwy witryny traci zakończenie. Pole author należy do obiektu z @type; sam ciąg znaków zostanie przyjęty, ale nic nie mówi o tym, czy pisała osoba, czy organizacja. Pole dateModified nie może być wcześniejsze niż datePublished – kombinacja pojawiająca się zawsze wtedy, gdy migracja wpisze datę importu do jednego z tych pól. A obraz powinien istnieć w więcej niż jednej proporcji, bo układ, w którym ląduje wynik, nie jest tym, o który proszą znaczniki.
FAQPage: reguła sięgająca aż na stronę
Blok FAQ to jedyny typ, którego poprawność zależy od czegoś poza samymi znacznikami: każde pytanie i każda odpowiedź muszą być widoczne na samej stronie. Znaczniki opisujące listę rozwijaną, która nigdy się nie otwiera, albo pytania istniejące wyłącznie w JSON, uchodzą za wprowadzające w błąd, a nie za niekompletne – a to działanie ręczne, a nie brakująca funkcja.
Od 2023 roku sam wynik rozszerzony FAQ pojawia się niemal wyłącznie przy witrynach urzędowych i medycznych, dla większości stron widoczna nagroda więc odpada. Znaczniki i tak się opłacają, tylko innym czytelnikom: wyszukiwarce wewnętrznej, asystentom czytającym stronę, aby odpowiedzieć na pytanie, i każdemu dalszemu systemowi, który inaczej musiałby zgadywać, która część tekstu jest pytaniem. Kto oczekuje po tym wpisu z gwiazdkami i strzałką, ten się zawiedzie; kto chce maszynowo czytelnej pary pytanie-odpowiedź, dostaje dokładnie to.
Product: cena, waluta, dostępność
Produkt bez bloku offers to produkt bez ceny, a cena jest jedynym powodem istnienia wyniku produktowego.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Kompaktowy switch PoE, 8 portów",
"image": ["https://www.example.com/images/switch.png"],
"brand": { "@type": "Brand", "name": "Example" },
"offers": {
"@type": "Offer",
"price": "149.00",
"priceCurrency": "EUR",
"availability": "https://schema.org/InStock",
"url": "https://www.example.com/switch/"
}
}
</script>
Pole availability przyjmuje adres schema.org, a nie samo słowo: InStock w oderwaniu nie jest wartością. Gdy dochodzi aggregateRating, potrzebuje zarówno ratingValue, jak i liczby ocen – jedno bez drugiego odpada, a ocena widniejąca na stronie, ale nieobecna w znacznikach, jest dla wpisu bez wartości. Oceny, których strona w ogóle nie potrafi pokazać, odwrotnie, nie mają w znacznikach czego szukać.
Sprawdzenie, zanim trafi na produkcję
Trzy kontrole wychwytują niemal wszystko i odpowiadają na różne pytania. Kontrola strukturalna czyta blok samodzielnie: czy są pola obowiązkowe, czy data jest datą ISO, czy cena jest liczbą. Rich Results Test mówi następnie, czy Google w ogóle rozpoznaje typ – to jedyne miejsce, w którym widać @type zapisane małą literą. A raporty ulepszeń w Search Console pokazują, co dzieje się w skali całej witryny, i tam błąd szablonu ujawnia się jako kilkaset identycznych ostrzeżeń, a nie jako jedno.
Żadna z nich nie odpowiada natomiast na pytanie, czy wynik zostanie pokazany. Poprawne znaczniki są warunkiem, a nie roszczeniem: Google rozstrzyga przy każdym zapytaniu i każdej stronie, czy pojawi się wynik rozszerzony, a poprawny blok, z którego nic nie wynika, jest przypadkiem normalnym, a nie usterką. Powód, dla którego pisze się dane strukturalne, to ten, który tę decyzję przetrwa – strona, której twierdzenia są czytelne dla maszyn, w chwili, gdy coraz więcej z nich czyta.