Raport „Skuteczność” wygląda na komplet danych, dopóki nie zaczniesz go sumować. Kliknięcia z listy zapytań rzadko zgadzają się z sumą na wykresie, a lista urywa się na tysiącu wierszy. To nie błąd interfejsu, tylko konsekwencja tego, jak Google udostępnia dane. API potrafi oddać znacznie więcej, ale tylko wtedy, gdy zapytasz we właściwy sposób.
Poniżej: gdzie realnie leżą limity, jak działa paginacja, kiedy dzielić zapytanie po datach albo po adresach URL i jak zbudować własną historię, która nie zniknie po szesnastu miesiącach.
Skąd biorą się braki w danych o zapytaniach
Rozbieżność między sumą kliknięć na wykresie a sumą w tabeli ma dwa niezależne źródła i warto je rozdzielić, zanim zaczniesz debugować własny skrypt.
Pierwsze to anonimizacja. Google nie pokazuje zapytań, które zadała zbyt mała liczba unikalnych użytkowników. Takie wyszukiwania wliczają się do sumy zbiorczej, ale nie pojawiają się w wymiarze query. Na małych i średnich serwisach potrafi to być większość ruchu, więc lista zapytań nigdy nie zsumuje się do liczby z wykresu. Żadna sztuczka po stronie API tego nie odblokuje: to decyzja o ochronie prywatności, nie limit techniczny.
Drugie źródło to zwykłe obcięcie listy. Interfejs webowy zwraca maksymalnie 1000 wierszy na widok, a API domyślnie 1000 wierszy na wywołanie. Tu już da się działać: paginacja i podział zapytania pozwalają zejść znacznie głębiej. To właśnie ta część jest odzyskiwalna i jej poświęcamy resztę tekstu.
Limity API: dzienne, na zapytanie i na wiersze
Search Console API ma trzy warstwy limitów i mylenie ich ze sobą jest najczęstszą przyczyną nieudanych integracji.
| Rodzaj limitu | Wartość orientacyjna | Co się dzieje po przekroczeniu |
|---|---|---|
| Wiersze na jedno wywołanie | 25 000 (domyślnie 1000) | Odpowiedź jest po cichu obcinana |
| Zapytania na minutę (per projekt) | rząd 1200 | Kod 429, wymagany backoff |
| Zapytania dzienne (per projekt) | rząd 30 000 | Kod 429 do końca doby |
| Zakres historii | 16 miesięcy | Starsze daty zwracają pustą tablicę |
Najważniejszy jest pierwszy wiersz tabeli. Parametr rowLimit przyjmuje wartość do 25 000, ale jeśli go nie ustawisz, dostaniesz 1000 wierszy i żadnego ostrzeżenia. To cicha awaria: skrypt działa, zwraca dane, a ty przez tydzień analizujesz jedną czwartą tego, co masz. Ustawiaj rowLimit jawnie w każdym wywołaniu.
Warto też zrozumieć, przeciwko czemu naliczane są limity dzienne. Kwota jest wspólna dla projektu w Google Cloud, a nie dla pojedynczej usługi w Search Console. Jeśli obsługujesz dwadzieścia domen z jednego projektu, dzielą one tę samą pulę. Przy większym portfolio serwisów rozsądnie jest rozdzielić klientów na osobne projekty, zamiast walczyć z kodem 429 po południu.
Aktualne wartości limitów i pełną specyfikację metody znajdziesz w dokumentacji metody searchanalytics.query w Google Search Central. Traktuj liczby powyżej jako rząd wielkości do zaplanowania architektury, a nie jako gwarancję.
Paginacja i poprawne użycie startRow
Paginacja w tym API jest prosta, ale ma jedną pułapkę, która psuje wyniki po cichu. Kolejne strony pobierasz, zwiększając startRow o wartość rowLimit, aż odpowiedź zwróci mniej wierszy, niż wynosi limit.
- Wywołanie pierwsze:
startRow: 0,rowLimit: 25000. - Jeśli wróciło dokładnie 25 000 wierszy, pobierz kolejne:
startRow: 25000. - Powtarzaj, aż liczba zwróconych wierszy będzie mniejsza niż
rowLimit. To sygnał końca zbioru. - Nie zatrzymuj się na pustej odpowiedzi tylko po jednej próbie, jeśli wcześniej dostałeś kod 5xx. Rozróżnij „koniec danych” od „błąd sieci”.
Pułapka dotyczy stabilności sortowania. API zwraca wiersze posortowane malejąco po kliknięciach, ale przy remisach kolejność nie jest gwarantowana między wywołaniami. W ogonie długiego zbioru, gdzie tysiące zapytań ma po jednym kliknięciu albo zero, kolejne strony mogą powtórzyć te same wiersze i pominąć inne. Dlatego po zebraniu wszystkich stron zawsze deduplikuj po kluczu złożonym z wartości wymiarów, na przykład para zapytanie plus strona, a nie po numerze wiersza.
Podział zapytań po datach i po stronach
Sposób na zejście poniżej limitów jest zawsze ten sam: zamiast jednego dużego zapytania wysyłasz wiele małych, których zbiory wyników się nie przecinają. Dwa naturalne wymiary podziału to czas i adresy URL.
Podział po datach
Zamiast pytać o 28 dni naraz, pytaj o każdy dzień osobno. Zapytanie dzienne prawie nigdy nie dobija do 25 000 wierszy, a przy okazji dostajesz dane w rozdzielczości dziennej, których agregat by nie dał. Koszt to 28 wywołań zamiast jednego, co przy limicie rzędu 30 000 dziennie jest bez znaczenia.
Uwaga na strefę czasową: Search Console operuje na czasie pacyficznym Stanów Zjednoczonych, a nie na czasie lokalnym serwisu. Jeśli twój magazyn danych zakłada polskie daty, dzień będzie systematycznie przesunięty. Zapisuj datę dokładnie w takiej postaci, w jakiej zwróciło ją API, a konwersję rób dopiero na etapie raportu.
Podział po stronach
Gdy nawet pojedynczy dzień jest za duży, dziel po adresach URL. Najpierw pobierz listę stron z wymiarem page, potem dla każdej z nich pobierz zapytania z filtrem dimensionFilterGroups na dokładny adres. Ta technika ma dodatkową zaletę: wyniki są od razu przypisane do konkretnego URL, więc nie musisz później rozplątywać par zapytanie plus strona.
Trzeba tylko pilnować liczby wywołań. Serwis z 5000 stron pomnożony przez 28 dni to 140 000 zapytań, czyli grubo ponad dzienny limit. W praktyce dzieli się po stronach tylko te adresy, które w agregacie przekroczyły próg, na przykład 200 wyświetleń, a resztę zostawia w zapytaniu zbiorczym. Ta sama zasada porządkuje zresztą inne integracje danych, o czym pisaliśmy w tekście o tym, jak praktycznie połączyć API GA4 i Search Console.
Filtrowanie po kraju, urządzeniu i typie wyszukiwania
Filtry to nie tylko wygoda analityczna, to również narzędzie do rozbijania dużych zbiorów na mniejsze porcje. Trzy pola, które w praktyce zmieniają najwięcej:
- searchType (w nowszej wersji
type): domyślnieweb. Grafika, wideo, wiadomości i wyniki dyskusji to osobne zbiory. Jeśli nie ustawisz tego pola jawnie, nigdy nie zobaczysz ruchu z Google Grafiki, choć w interfejsie masz go pod ręką. - country: filtr po kodzie ISO trzyliterowym, na przykład
pol. Dla polskiego serwisu z ogonem zagranicznych wyświetleń to jedyny sposób, żeby pozycje i CTR opisywały realny rynek, a nie mieszankę rynków. - device: podział na
MOBILE,DESKTOPiTABLET. Uśredniona pozycja bez tego podziału bywa myląca, bo jedno urządzenie potrafi ciągnąć średnią w drugą stronę.
Filtry łączysz w dimensionFilterGroups. W obrębie jednej grupy warunki działają jak koniunkcja, a operator equals jest bezpieczniejszy niż contains, który przy adresach URL potrafi złapać też podstrony potomne. Jeśli filtrujesz po dokładnym adresie, użyj equals i pełnego URL razem z protokołem oraz z ukośnikiem na końcu (albo bez, zależnie od tego, jaką formę kanoniczną ma twój serwis, byle konsekwentnie).
Składowanie danych i budowa własnej historii
Minimalny schemat tabeli to: data, zapytanie, strona, kraj, urządzenie, typ wyszukiwania, kliknięcia, wyświetlenia, pozycja. Klucz unikalny na komplecie wymiarów pozwala robić upsert i bezpiecznie powtarzać przerwane pobrania. Trzy zasady, które oszczędzają najwięcej problemów później:
- Pobieraj z opóźnieniem 3 dni. Dane z ostatnich dni są niekompletne i dopełniają się jeszcze przez kilkadziesiąt godzin. Zapisanie ich jako finalnych zafałszuje historię na zawsze.
- Nadpisuj okno ruchome. Przy każdym uruchomieniu odśwież ostatnie 5 do 7 dni, nie tylko nowy dzień. Wtedy dopełnienia trafią do bazy.
- Nie przechowuj wyliczonego CTR. Zapisuj kliknięcia i wyświetlenia, a CTR licz w raporcie. Uśrednianie zapisanych CTR między dniami daje wartości, które nie mają sensu.
Jeśli nie chcesz budować własnego magazynu od zera, część tej pracy da się zamknąć w gotowym przepływie no-code, tak jak w naszym opisie automatycznego raportu SEO wysyłanego z Make do Slacka. Do pracy ad hoc, gdy potrzebujesz zadać danym pytanie, a nie zbudować pipeline, wygodniejszym podejściem bywa wystawienie GSC i GA4 jako narzędzi dla asystenta, co opisaliśmy w tekście o MCP dla marketera, spinającym GSC, GA4 i WordPressa.
Typowe błędy i kody odpowiedzi
Większość awarii w integracjach z tym API sprowadza się do kilku powtarzalnych sytuacji.
| Objaw | Prawdopodobna przyczyna | Co zrobić |
|---|---|---|
| 403 z komunikatem o uprawnieniach | Konto serwisowe nie jest dodane jako użytkownik usługi | Dodaj adres konta serwisowego w ustawieniach usługi w Search Console |
| 429 | Przekroczony limit minutowy lub dzienny | Backoff wykładniczy, rozłożenie pobrań w czasie, osobny projekt Cloud |
| Pusta tablica rows | Brak danych dla zakresu albo zła forma adresu usługi | Sprawdź prefiks: sc-domain:example.pl to co innego niż https://example.pl/ |
| Dokładnie 1000 wierszy | Nieustawiony rowLimit | Ustaw jawnie i wprowadź paginację |
| 400 przy filtrach | Zły format wartości, na przykład dwuliterowy kod kraju | Kody krajów są trzyliterowe, urządzenia wielkimi literami |
W zadaniach automatycznych uwierzytelniaj się kontem serwisowym z przepływem OAuth 2.0 w wariancie dla serwerów, a nie tokenem użytkownika. Ten drugi wygasa i pipeline padnie w najmniej wygodnym momencie.
Podsumowanie
Kompletu danych o zapytaniach nie da się pobrać, bo anonimizacja jest nieodwracalna. Da się natomiast pobrać wszystko, co Google w ogóle udostępnia, a to zwykle kilka razy więcej niż widać w interfejsie: rowLimit ustawiony jawnie, paginacja po startRow z deduplikacją, podział po dniach (przy dużych serwisach także po adresach URL) i zapis u siebie z trzydniowym opóźnieniem.
Najtańszy pierwszy krok: dorzuć do istniejącego skryptu jawny rowLimit i porównaj liczbę zwróconych wierszy z tą sprzed zmiany. Jeśli wcześniej dostawałeś równe 1000, właśnie odzyskałeś dane, o których nie wiedziałeś, że ci ich brakuje.
FAQ
Ile wierszy realnie zwraca Search Console API na jedno wywołanie?
Do 25 000, jeśli ustawisz parametr rowLimit jawnie. Bez tego parametru dostaniesz 1000 wierszy i żadnego komunikatu o obcięciu, co jest najczęstszą przyczyną niekompletnych raportów.
Dlaczego suma kliknięć z listy zapytań nie zgadza się z sumą na wykresie?
Bo Google ukrywa zapytania zadane przez zbyt małą liczbę unikalnych użytkowników. Te kliknięcia wliczają się do sumy zbiorczej, ale nie pojawiają się w wymiarze query. Tej różnicy nie da się usunąć żadnym parametrem API.
Jak daleko wstecz sięgają dane w API?
Szesnaście miesięcy. Starsze zakresy zwracają pustą tablicę wyników. Jeśli chcesz mieć historię dłuższą niż półtora roku, musisz pobierać dane cyklicznie i zapisywać je we własnej bazie.
Kiedy dzielić zapytania po adresach URL zamiast po datach?
Gdy pojedynczy dzień nadal dobija do limitu 25 000 wierszy. Podział po stronach stosuj wybiórczo, tylko dla adresów powyżej progu wyświetleń, bo iloczyn liczby stron i liczby dni bardzo szybko przekracza dzienny limit wywołań.
Dlaczego API zwraca pustą odpowiedź, choć w interfejsie widzę dane?
Najczęściej z powodu złej formy adresu usługi. Usługa typu domena zapisywana jest jako sc-domain:example.pl i wymaga zakodowania dwukropka, a usługa typu prefiks jako pełny adres z protokołem. Pomyłka nie zwraca błędu, tylko pustą tablicę.
