Wiadomość została wysłana.

Jaki markup schema.org jest potrzebny, żeby cena i dostępność trafiły do odpowiedzi asystenta?

Na karcie produktu potrzebny jest węzeł Product i Offer z polami price, priceCurrency i availability. Ten JSON-LD ma być w HTML z serwera, a te trzy wartości mają być takie same jak w feedzie. Cena, która pojawia się dopiero po JavaScript, nie weszła do HTML, który zapisał crawler.

Węzły na karcie

schema.org Product to sam towar. schema.org Offer to warunki handlowe: cena, waluta i to, czy da się kupić. schema.org AggregateRating to podsumowanie opinii i jest opcjonalny.

Definicje: https://schema.org/Product, https://schema.org/Offer i https://schema.org/AggregateRating. JSON-LD wstawiaj w HTML adresu produktu, nie tylko na stronie kategorii.

Google ma osobny test merchant listings: https://developers.google.com/search/docs/appearance/structured-data/merchant-listing i stronę product snippet: https://developers.google.com/search/docs/appearance/structured-data/product. To lista, którą Google sprawdza teraz. To nie jest obietnica, że te same pola czytają ChatGPT, Perplexity albo Gemini.

Strona merchant listing wymaga Product.name, image i zagnieżdżonego Offer, nie AggregateOffer. Offer potrzebuje ceny większej od zera, w price albo w priceSpecification.price, oraz pary priceCurrency. availability jest tam zalecane.

Offer: cena, waluta, dostępność

price to kwota, którą płaci kupujący, w jednostkach głównych, z kropką. 18.00 to osiemnaście, nie tysiąc osiemset. Symbolu waluty nie wkładaj do price.

priceCurrency to kod ISO 4217, na przykład PLN, EUR albo USD. To osobne pole. Para to price 18.00 i priceCurrency PLN. Ciąg 18.00 PLN pasuje do pliku feedu, nie do tych dwóch pól.

availability to URL typu ItemAvailability. Dostępny: https://schema.org/InStock. Niedostępny: https://schema.org/OutOfStock. Przedsprzedaż: https://schema.org/PreOrder. Oczekiwanie na dostawę: https://schema.org/BackOrder. Użyj tego pełnego URL. Strona merchant listing Google przyjmuje też krótką nazwę InStock. Status sklepu instock nie jest żadnym z nich.

url w Offer to karta, z wybranym wariantem, gdy cena dotyczy jednego wariantu. itemCondition może być https://schema.org/NewCondition, gdy towar jest nowy. priceValidUntil jest opcjonalny i nie zastępuje aktualizacji feedu.

AggregateOffer z lowPrice i highPrice opisuje zakres. Nie mówi, który wariant jest dostępny. Używaj go tylko wtedy, gdy chodzi o zakres. Dla jednego wariantu jest jeden Offer.

Product i AggregateRating

Product.name to nazwa na stronie. image to bezpośredni URL obrazu i można go powtórzyć. description to zwykły tekst. sku to Twój identyfikator. brand to węzeł Brand z name albo tekst. offers wskazuje Offer albo tablicę Offer, gdy wariantów jest kilka i każdy naprawdę się sprzedaje.

AggregateRating.ratingValue to średnia. reviewCount to liczba opinii, z których ta średnia powstała. ratingCount w schema.org też jest dopuszczalny jako drugi licznik. bestRating domyślnie wynosi 5, gdy pole pominiesz. Nie podawaj oceny, gdy opinii nie ma. Nie mieszaj opinii o sklepie do licznika produktu.

Te same fakty mogą leżeć w pliku OpenAI jako star_rating i review_count. Tam te pola są opcjonalne. Gdy strona i plik podają ocenę, ma to być ta sama grupa opinii.

Feed i strona to dwie kopie

Google Merchant Center ma własny feed. W specyfikacji danych produktu są id, title, description, link, image_link, availability, price i brand. Cena wygląda tam jak 18.00 PLN. availability używa in_stock, out_of_stock, preorder i backorder. Opis: https://support.google.com/merchants/answer/7052112.

W pliku discovery OpenAI są item_id, url, image_url i price w postaci 18.00 PLN, a przedsprzedaż pisze się pre_order. seller_name jest tam wymagany i w podstawowym wierszu Google nie ma pary.

Offer na stronie, feed Google i feed OpenAI to trzy kopie jednego faktu. Gdy się różnią, nie wybierasz, którą kopię powtórzy asystent.

Strona sprzedawców OpenAI mówi, że feed jest opcjonalny, gdy ChatGPT już obchodzi witrynę, i że feed daje większą kontrolę nad tym, jak produkty wyglądają. Nie mówi, że feed wygrywa, gdy dwie ceny się różnią. Perplexity, Gemini i Google AI Overviews to nie ten feed. Na stronie AI features Google dane strukturalne mają zgadzać się z widocznym tekstem.

Pełny przykład

Jeden produkt, jedna oferta, markup w HTML z serwera. Podmień URL example.com. W price nie ma symbolu waluty. availability to pełny URL schema.org.

Gdy kubek ma wariant niebieski i biały w różnych cenach, nie chowaj obu cen z HTML i nie podmieniaj ich skryptem. Albo każdy wariant ma własny URL i własny Offer, albo w tablicy offers jest jeden Offer na wariant, z własnymi price, availability i url.

{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Ceramic mug, 350 ml",
  "image": "https://example.com/images/mug.jpg",
  "description": "Glazed ceramic mug with a handle. Dishwasher safe.",
  "sku": "MUG-350",
  "brand": { "@type": "Brand", "name": "Northline" },
  "offers": {
    "@type": "Offer",
    "url": "https://example.com/products/mug",
    "priceCurrency": "PLN",
    "price": "72.00",
    "availability": "https://schema.org/InStock",
    "itemCondition": "https://schema.org/NewCondition"
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.6",
    "reviewCount": "28"
  }
}

Jak to sprawdzić

Otwórz URL produktu w Rich Results Test: https://search.google.com/test/rich-results. Usługa pobierze URL albo wkleisz HTML. Przeczytaj obiekt Product. price, priceCurrency i availability mają być dzisiejszymi wartościami ze strony, nie starą wartością z szablonu.

Walidator schema.org https://validator.schema.org/ sprawdza słownik. Graf może być poprawny i mimo to mieć złą cenę. Porównaj wyciągniętą cenę z ceną, którą widzi kupujący.

Pobierz też surowy HTML. Zrób curl adresu produktu albo otwórz view-source i znajdź ciąg ceny oraz schema.org/InStock. Jeśli pojawiają się dopiero po hydracji, w pierwszej odpowiedzi ich nie było.

Co psuje cenę

Cena wpisywana tylko przez JavaScript w przeglądarce nie ma jej w pierwszym HTML. Google pisze, że Googlebot wykonuje JavaScript: https://developers.google.com/search/docs/crawling-indexing/javascript/javascript-seo-basics. Ten dokument jest o Googlebot. Nie mówi tego samego o każdym crawlerze AI.

OpenAI, Perplexity i Anthropic nie opisują silnika JavaScript dla GPTBot, OAI-SearchBot, ChatGPT-User, PerplexityBot ani ClaudeBot. Wstaw cenę do HTML, który wysyła serwer.

Dalej psuje rozjazd z feedem. Strona mówi 72.00 PLN, a plik 79.99 USD, albo strona jest dostępna, a plik mówi out_of_stock. Napraw źródło, z którego czytają obie kopie. Nie poprawiaj samego markup.

Warianty psują cenę, gdy jeden URL oddaje wiele cen, a Offer nazywa tylko pierwszą. Kolor wybrany w przeglądarce, który nie zmienia HTML serwera, zostawia asystentowi wariant domyślny. Daj wariantowi stabilny URL i wstaw go w Offer.url.

Inne ciche błędy: availability słowem sklepu zamiast URL schema.org, cena z przecinkiem dziesiętnym, Offer na kategorii i brak go na URL produktu, AggregateRating z ratingValue i reviewCount równym zero.

OpenAI podaje około 24 godzin, zanim zmiana robots.txt wpłynie na wyszukiwanie. Terminu dla poprawionej ceny nie publikuje. Wysyłaj pełną migawkę co najmniej raz dziennie i sprawdź ten sam SKU ponownie.

  • W HTML adresu produktu są Product i Offer, zanim wystartuje skrypt.
  • price to liczba dziesiętna w jednostkach głównych, priceCurrency to kod ISO.
  • availability to https://schema.org/InStock albo odpowiadający URL braku, przedsprzedaży albo oczekiwania.
  • Wariant z własną ceną ma własny Offer albo własny URL.
  • Nie ma AggregateRating, gdy nie ma opinii.
  • Cena w Offer zgadza się z ceną Google Merchant i z feedem OpenAI.
  • Rich Results Test pokazuje cenę, którą widzi kupujący.
Czy potrzebny jest JSON-LD, czy wystarczy Microdata?

schema.org dopuszcza więcej niż jedną składnię. JSON-LD w HTML z serwera łatwiej zestawić z feedem. Liczy się to, czy cena i dostępność są w pobranym HTML pod nazwami, które da się odczytać.

Czy strona kategorii ma nieść Offer każdego produktu?

Oferta żyje pod URL, pod którym produkt się sprzedaje. Siatka kategorii może powtarzać nazwy. Nie powinna być jedynym miejscem, w którym jest cena. Asystenci cytują URL produktu.

Jakiego URL dostępności użyć, gdy towaru nie ma?

https://schema.org/OutOfStock. Zostaw Offer na stronie, z aktualną ceną. Usunięcie Offer nie mówi, że towaru nie ma. Mówi, że nie ma informacji.

Czy AggregateRating zmienia cenę, którą poda asystent?

Nie. Cena pochodzi z Offer.price i priceCurrency. AggregateRating to podsumowanie opinii. Pomiń je, gdy reviewCount byłby zerem.