Oba sklepy działają na Shoperze, oba sprzedają odzież w rozmiarach, w obu rozmiary są osobnymi rekordami magazynowymi. Wbudowany plik Google wyglądał jednak w każdym inaczej, więc i naprawa była inna: w pierwszym sklepie własny plik zamiast wbudowanego, w drugim tylko plik uzupełniający do wbudowanego. Zanim cokolwiek zmienisz, sprawdź, który przypadek masz.
W Merchant Center prawie cały katalog jest „niedostępny”, choć sklep normalnie sprzedaje. W badanym pliku ponad 99% pozycji miało out of stock, a pole EAN było puste we wszystkich pozycjach poza jedną.
Rozmiary i dostępność się zgadzają, ale przy produktach odzieżowych brakuje koloru, płci i grupy wiekowej, mimo że w sklepie te cechy są uzupełnione jako atrybuty produktu.
Co Shoper wysyła do Google we wbudowanym pliku
Integracja Google w Shoperze generuje plik XML pod adresem sklepu w ścieżce /console/integration/execute/name/GoogleProductSearch. Merchant Center pobiera go jako źródło produktów. Plik powinien być pobierany z domeny docelowej sklepu: w jednym ze sklepów adres roboczy w domenie shoparena.pl zwracał błąd 400.
Zawartość pliku sprawdziliśmy na dwóch pełnych pobraniach. W obu każda pozycja miała identyfikator, tytuł, opis, link, zdjęcie, cenę, dostępność, stan produktu, markę, pola gtin i mpn, typ produktu i koszt dostawy. Różnica była w poziomie, na którym plik opisuje produkt:
| Cecha pliku | Sklep A | Sklep B |
|---|---|---|
| jedna pozycja to | produkt (identyfikator produktu) | rozmiar (identyfikator stock_<id>) |
g:size i g:item_group_id | brak | w 91% pozycji |
g:gtin | puste w 99,99% pozycji | wypełnione, EAN rozmiaru |
| pozycje „out of stock” | ponad 99% | 29% |
g:color, g:gender, g:age_group (wymagane dla odzieży w bezpłatnych informacjach) | brak | brak |
g:google_product_category (opcjonalna) | brak | brak |
Tak wyglądają pojedyncze pozycje z obu plików (skrócone: bez opisu i kosztu dostawy, z zanonimizowanym adresem, identyfikatorami i nazwą):
<!-- Sklep A: pozycja na produkt -->
<entry>
<g:id>1234</g:id>
<title>Kurtka narciarska damska - biała</title>
<link>https://sklep.example/pl/p/kurtka/1234</link>
<g:availability>out of stock</g:availability>
<g:price>1599.99 PLN</g:price>
<g:gtin></g:gtin>
</entry>
<!-- Sklep B: pozycja na rozmiar -->
<entry>
<g:id>stock_5678</g:id>
<title>Kurtka męska - czarna</title>
<link>https://sklep.example/pl/p/kurtka/910</link>
<g:availability>in stock</g:availability>
<g:price>699.99 PLN</g:price>
<g:gtin>5901234123457</g:gtin>
<g:item_group_id>910</g:item_group_id>
<g:size>46</g:size>
</entry>
Plik Shopera zapisuje dostępność ze spacją: in stock, out of stock. Specyfikacja Google używa wartości in_stock i out_of_stock; we własnym pliku używamy zapisu ze specyfikacji.
Czego nie ustaliliśmy: od czego zależy, że w jednym sklepie plik ma pozycje na poziomie produktu, a w drugim na poziomie rozmiaru. Pomoc Shopera tego nie opisuje, a oba sklepy trzymają rozmiary jako warianty magazynowe. Dlatego diagnozę zaczynaj od samego pliku, nie od ustawień.
Przypadek A: pozycja na produkt i stan z produktu głównego
W sklepie A plik miał tyle pozycji, ile sklep ma produktów, a nie rozmiarów. Dostępność i EAN pochodziły z produktu głównego. Tymczasem stan sklepu siedział w rozmiarach: wiersz produktu głównego miał zero sztuk, a kody EAN były przypisane do rozmiarów. Wynik: prawie każda pozycja trafiała do Google jako niedostępna, bez rozmiaru i bez EAN.
To ten sam mechanizm, który na karcie produktu daje złą cenę na listingu i „0 szt.” w panelu: dane leżą na poziomie rozmiaru, a coś czyta poziom produktu. Opisujemy go w poradniku o wariancie domyślnym w Shoperze po imporcie z BaseLinkera, a skutek w danych strukturalnych karty w poradniku o braku ceny i dostępności w Merchant Center.
W tym sklepie stan przeniósł się na rozmiary w drugiej połowie września, w tych samych dniach, w których integracja masowo zapisywała produkty. Bez logu synchronizacji nie potwierdziliśmy, który przebieg to zrobił. Jeśli Twój plik nagle zrobił się „niedostępny”, sprawdź najpierw, czy nie zmienił się sposób zapisywania stanów przez integrację.
Przypadek B: rozmiary są, brakuje koloru, płci i wieku
W sklepie B plik był zbudowany dobrze: pozycja na rozmiar, wspólny identyfikator grupy dla produktu, EAN i dostępność rozmiaru. Brakowało czterech pól, których Shoper nie wkłada do pliku: koloru, płci, grupy wiekowej i kategorii Google.
Powód leży w modelu katalogu. Kolor był osobnym produktem, nie wariantem, a płeć cechą produktu. Wbudowany plik przenosi do Google warianty, więc rozmiar trafia do g:size, a cechy produktu nie trafiają nigdzie. Panel nie ma mapowania „cecha sklepu → pole Google”.
Dla odzieży to nie jest drobiazg. Kolor, płeć i grupa wiekowa są według pomocy Merchant Center wymagane w bezpłatnych informacjach o produktach dla wszystkich produktów z kategorii „Odzież i akcesoria”. W reklamach produktowych są wymagane dla wybranych krajów, wśród których nie ma Polski. Kategoria Google jest natomiast opcjonalna: pomaga, gdy Google sam źle klasyfikuje produkt, ale jej brak nie blokuje wyświetlania.
Dwie rzeczy warto sprawdzić przy okazji, choć nie były tu przyczyną problemu. Po pierwsze grupowanie: w sklepie B item_group_id łączy rozmiary jednego koloru, bo kolor jest osobnym produktem. Kolory tego samego modelu trafiają więc do Google jako osobne grupy, a nie jeden produkt z wyborem koloru. Takie grupowanie odzwierciedla strukturę katalogu w Shoperze, ale nie wymagania Google: pomoc Merchant Center zaleca wspólny item_group_id dla wariantów tego samego produktu różniących się kolorem lub rozmiarem, także gdy mają osobne adresy. Połączenie kolorów w jedną grupę wymaga identyfikatora modelu wspólnego dla wszystkich kolorów, którego wbudowany plik nie podaje. Po drugie linki: Google zaleca, żeby adres wariantu otwierał stronę z tym wariantem już wybranym. W obu sklepach pozycje rozmiarów prowadzą do karty produktu bez wybranego rozmiaru.
Jak rozpoznać swój przypadek
| Sprawdź w pliku | Wynik | Co z tego wynika |
|---|---|---|
| liczba pozycji | zbliżona do liczby produktów | plik opisuje produkty, nie rozmiary: przypadek A |
| to samo | zbliżona do liczby rozmiarów | plik opisuje rozmiary: sprawdź dalej pola wariantu i cechy |
udział out of stock | wyraźnie wyższy niż w sklepie | sprawdź, skąd plik bierze stan: z produktu głównego czy z rozmiarów |
g:gtin | pusty przy produktach, które mają EAN w rozmiarach | plik czyta identyfikatory z poziomu produktu |
g:size i g:item_group_id | OK, gdy są w pozycjach z rozmiarami i grupa łączy rozmiary jednego produktu | bez nich Google nie zgrupuje wariantów |
g:color, g:gender, g:age_group | OK, gdy są przy produktach odzieżowych | braki do uzupełnienia: przypadek B |
Plik bywa duży: w sklepie B miał 145 MB. Do sprawdzenia wystarczy go przeczytać strumieniowo i policzyć pola; nie trzeba otwierać całości w edytorze.
Własny plik albo plik uzupełniający: co zrobiliśmy
Sklep A: własny plik zamiast wbudowanego. Wbudowanego pliku nie dało się poprawić z zewnątrz, bo cały był zbudowany na złym poziomie. Powstał własny plik XML generowany co noc z tej samej paczki danych, z której korzysta wyszukiwarka sklepu:
- jedna pozycja to jeden dostępny rozmiar, z identyfikatorem rekordu magazynowego i wspólnym
item_group_idproduktu; - EAN z rozmiaru; pozycje bez EAN (3 na ok. 2 tys.) idą bez kodu i bez oznaczenia
identifier_exists, a ich lista trafia do raportu do uzupełnienia w źródle; - płeć i grupa wiekowa z działów sklepu, kolor z cech produktu, rozmiar w tytule i w
g:size; - cena po kontroli: próbka cen z pliku porównywana z ceną końcową na karcie produktu, zanim plik zostanie opublikowany;
- bezpiecznik: przy podejrzanie małej liczbie pozycji plik się nie nadpisuje i zostaje poprzedni.
Takich pozycji nie oznaczamy jako produktów bez kodu. Według pomocy Merchant Center identifier_exists = no jest dla produktów, które naprawdę nie mają kodu producenta, a markowa odzież zwykle go ma: brak EAN w bazie sklepu to luka w danych, nie dowód, że kodu nie ma. Dlatego generator zostawia pole puste i co noc zapisuje listę takich rozmiarów, żeby uzupełnić je w źródle.
Świadoma decyzja: niedostępne rozmiary nie trafiają do pliku wcale, zamiast trafiać z out_of_stock. Przy katalogu, w którym większość rozmiarów jest wyprzedana, plik jest dzięki temu wielokrotnie mniejszy, a Google nie dostaje tysięcy pozycji, których nie da się kupić. Ceną jest to, że rozmiar, który wróci na stan, pojawia się w Google dopiero po następnym pobraniu pliku i ponownym przetworzeniu pozycji przez Google, co trwa dłużej niż zmiana dostępności istniejącej pozycji. Google zaleca zostawiać produkty chwilowo niedostępne z out_of_stock; przy towarze, który często wraca na stan, to lepszy wybór.
Sklep B: plik uzupełniający do wbudowanego. Wbudowany plik był dobry, więc został źródłem głównym. Brakujące pola dostarcza plik uzupełniający, który Merchant Center dopina do pozycji po identyfikatorze stock_<id>: kolor, płeć, grupa wiekowa i kategoria Google. Plik powstaje co noc z wbudowanego pliku Shopera i z nocnego zrzutu cech produktów, bez dodatkowych zapytań do API. Gdy produkt nie ma cechy koloru albo płci, wartość pochodzi z nazwy produktu, ale tylko z jednoznacznych wzorców: kolor z końcówki nazwy po myślniku (sklep konsekwentnie nazywa produkty „… - czarne”), płeć ze słów „damska”, „męska”, „chłopięca”, „dziewczęca” i „unisex”. Słowo „dziecięca” mówi o wieku, nie o płci: ustala grupę wiekową kids, a płeć ustawia na unisex, co jest założeniem, nie odczytem z nazwy. Gdy nazwa żadnego wzorca nie ma, pola zostają puste zamiast zgadywane. Cecha w sklepie zawsze wygrywa z nazwą.
Trzy ograniczenia techniczne, które trzeba uwzględnić przy automatyzacji pliku:
- nieskompresowany plik uzupełniający (ok. 5,5 MB) serwer plików sklepu odrzucał kodem 413; spakowany do
.gzprzechodzi, a Merchant Center czyta go bez rozpakowywania; - wbudowany plik Shopera trzeba czytać z domeny sklepu, bo adres roboczy zwracał 400;
- plik uzupełniający musi nadążać za wbudowanym, bo ten zmienia się codziennie: nowe produkty i rozmiary bez wiersza w uzupełnieniu zostają bez koloru i płci.
Efekt w obu sklepach
- Sklep A: pierwsze pobranie własnego pliku przez Merchant Center (15 października 2026) przeszło bez błędów pliku. Pozycje mają rozmiar, grupę wariantów i dostępność rozmiaru; EAN brakuje w 3 pozycjach na ok. 2 tys., i te mają jawne
identifier_exists. - Sklep B: po dodaniu wartości z nazwy produktu odsetek pozycji, które dostały w pliku uzupełniającym co najmniej jedno pole, wzrósł z 90,8% (na próbie) do 100% w nocnym przebiegu. Przy pobraniu z 20 października 2026 Merchant Center dopasował o ok. 11% więcej pozycji niż wcześniej, rozpoznał wszystkie atrybuty i nie zgłosił żadnego problemu z plikiem uzupełniającym.
Pełne pokrycie nie oznacza, że każda wartość jest poprawna, dlatego z nazwy bierzemy tylko jednoznaczne wzorce. Liczby zatwierdzonych produktów w sklepie A nie podajemy, bo jej nie mierzyliśmy. W sklepie B o zatwierdzeniu produktów decydowało dodatkowo ustawienie usługi porównywania cen, opisane w trzecim wpisie tej serii.
Który wariant wybrać i kiedy to wymaga programisty
Gdy wbudowany plik ma pozycje na rozmiar z poprawną dostępnością i EAN, a brakuje tylko cech. Zostajesz przy integracji Shopera i dokładasz jedno źródło w Merchant Center. Proste przypadki da się zrobić arkuszem; przy tysiącach produktów i codziennych zmianach potrzebny jest automat.
Gdy wbudowany plik opisuje produkty zamiast rozmiarów albo bierze stan i EAN z niewłaściwego poziomu. Wtedy uzupełnienie nie pomoże, bo nie ma do czego dopiąć brakujących pól. Własny plik wymaga danych z API sklepu, kontroli cen przed publikacją i nocnego automatu z bezpiecznikami.
W obu przypadkach warto zacząć od pobrania pliku i tabeli z sekcji 04. Jak Shoper przechowuje rozmiary, stany i ceny po stronie API, opisuje poradnik Najczęstsze błędy Shoper API.