seojuice

Zbudowałem dashboard Google Search Console za 0 zł. Oto kod.

Vadim Kravcenko
Vadim Kravcenko
· Updated · 15 min read

W skrócie: Google Search Console udostępnia te same dane o zapytaniach, stronach, pozycjach i wyświetleniach, za które SEMrush i Ahrefs pobierają 129–449 USD miesięcznie. Interfejs GSC API oferuje darmowy limit 1 200 zapytań na minutę, 25 000 wierszy na odpowiedź i cztery endpointy, które pokrywają ok. 90% potrzeb solo-foundera. W tym artykule przechodzimy przez konfigurację OAuth z kontem usługi, opis czterech kluczowych endpointów, gotowy skrypt Pythona generujący macierz CTR zapytanie × strona oraz trzy wzorce automatyzacji (cron + Slack, Google Sheets, lekki widok Django), które zamieniają surowe wiersze z API w praktyczny dashboard. Jeśli nie chcesz utrzymywać integracji samodzielnie, SEOJuice oferuje to samo jako usługę zarządzaną.

Co GSC już daje za darmo (a płatne narzędzia przepakowują)

Frustrujące w pakiecie SEO za 449 USD/mies. jest to, że ok. 70% danych w dashboardzie pochodzi z Google Search Console. Płatne narzędzia dorzucają trzy rzeczy: monitorowanie pozycji z proxy, graf linków zebrany z własnego crawl’u oraz UI niewymagające SQL. Tylko to ostatnie jest faktycznie potrzebne solo-founderowi — i najłatwiej je sklonować.

API udostępnia, dla każdej zweryfikowanej usługi:

  • 16 miesięcy danych historycznych: każde zapytanie z kliknięciem lub wyświetleniem, wraz z pozycją, CTR i datą.
  • Rozbicie na strony w tym samym oknie: które URL-e rankowały na jakie zapytania i gdzie wylądowały kliknięcia.
  • Status indeksu dla URL-a: data ostatniego crawl’u, werdykt indeksowania, kanoniczny wskazany przez Google, mobile usability, parsowanie danych strukturalnych.
  • Stan sitemap: które mapy Google pobrał, kiedy i ile URL-i odkryto vs. zaindeksowano.
  • Segmentacja po urządzeniu, kraju i typie wyniku dla tych samych danych zapytanie/strona.

Brakuje wszystkiego poza Twoją domeną: pozycji konkurencji, przyrostu linków rywali, share-of-voice. Dla większości pre-PMF to metryki próżności, które nie wpływają na kolejny release. Opisałem, jak zredukować stack SEO do dwóch narzędzi; wniosek się utrzymał: GSC plus jedno środowisko pisania to wystarczający sygnał do działania.

„Dane w Search Console pochodzą bezpośrednio od Google. To najdokładniejsze źródło do zrozumienia, jak Twoja witryna radzi sobie w wyszukiwarce Google.”

Z dokumentacji Search Console Help.

Konfiguracja GSC API z kontem usługi

Dostępne są dwa scenariusze autoryzacji: OAuth typu user-flow (przekierowanie z przeglądarki, refresh token) i OAuth z kontem usługi (server-to-server, bez przeglądarki). Dla cron’a na pojedynczym VPS-ie konto usługi jest krótsze i trwalsze — brak wygasania refresh tokena, brak ekranu zgody.

Całość zajmuje ok. 10 minut i nic nie kosztuje:

  1. Wejdź w Google Cloud Console i utwórz nowy projekt (lub użyj istniejącego). Darmowy tier wystarczy.
  2. Włącz Google Search Console API w bibliotece API.
  3. W IAM & Admin → Service Accounts utwórz konto usługi gsc-dashboard-reader. Bez ról projektowych.
  4. Wygeneruj klucz JSON i pobierz go. Traktuj jak hasło; nie commituj.
  5. W Search Console, Settings → Users and permissions, dodaj e-mail konta usługi (kończący się na @<project-id>.iam.gserviceaccount.com). Uprawnienie Restricted wystarczy do odczytu.

O tym ostatnim kroku founderzy zapominają. Konto usługi to tożsamość Google, ale jeśli nie dasz mu dostępu do właściwości, API zwróci autorytatywne 403 user does not have sufficient permission for site. Nadaj uprawnienia per własność; przy wielu powtórz.

Diagram of the service-account OAuth flow: GCP project, service account, JSON key, Search Console permission grant
Przepływ OAuth z kontem usługi. Plik z danymi logowania uwierzytelnia w Google; uprawnienie w Search Console autoryzuje dostęp do danych.

Cztery endpointy, które pokrywają 90% potrzeb

Powierzchnia API GSC jest mała. Cztery endpointy obejmują dane zapytań, stan sitemap, inspekcję URL-i oraz listę dostępnych usług. Resztę dokumentacji czytaj dopiero, gdy będziesz mieć konkretny powód.

EndpointCo zwracaKoszt limituDo czego przydatny
searchanalytics.queryDo 25 000 wierszy kliknięć, wyświetleń, pozycji, CTR wg zapytania, strony, daty, urządzenia, kraju1 jednostka / zapytanieGłówne dane dashboardu; które zapytania generują ruch, które strony konwertują wyświetlenia na kliknięcia
sitemaps.listWszystkie sitemap’y z statusem, datą ostatniego pobrania, liczbą URL-i1 jednostka / zapytanieAlerty zdrowia sitemap; wykrywanie porzuconych lub częściowo zaindeksowanych map
urlInspection.index.inspectNa pojedynczy URL: stan indeksu, ostatni crawl, kanoniczny, mobile usability, werdykty AMP i danych strukturalnych2 000 / dzień (osobny limit)Kontrole kluczowych stron; automatyczne audyty indeksacji
sites.listWszystkie usługi, do których ma dostęp tożsamość1 jednostka / zapytanieDashboardy multi-property; iteracja po portfelu

Limit 1 200/min na endpointy odczytu jest praktycznie nieskończony dla solo-foundera. Jedyny realny sufit to 2 000/dobę na URL Inspection, co wystarcza na dzienny audyt 1 500-stronowej witryny.

Przykład w Pythonie: Top queries i macierz zapytanie × strona

Najbardziej użyteczne zapytanie to rozbicie zapytanie × strona z ostatnich 28 dni. Pokazuje, która strona rankuje na które słowo i jak wygląda CTR w przecięciu. Komórki z dużą liczbą wyświetleń i niskim CTR to najbliższe cele optymalizacji.

Zainstaluj dwie zależności:

pip install google-auth google-api-python-client

Minimalny skrypt: autoryzacja, zapytanie, print. Zapisz pobrany klucz jako gsc-credentials.json w tym samym katalogu:

from datetime import date, timedelta
from google.oauth2 import service_account
from googleapiclient.discovery import build

SCOPES = ["https://www.googleapis.com/auth/webmasters.readonly"]
SITE_URL = "sc-domain:example.com"  # or "https://example.com/"
KEY_FILE = "gsc-credentials.json"

creds = service_account.Credentials.from_service_account_file(
    KEY_FILE, scopes=SCOPES
)
service = build("searchconsole", "v1", credentials=creds)

end = date.today() - timedelta(days=2)  # GSC lags ~2 days
start = end - timedelta(days=27)

request = {
    "startDate": start.isoformat(),
    "endDate": end.isoformat(),
    "dimensions": ["query"],
    "rowLimit": 25,
    "orderBy": [{"field": "clicks", "descending": True}],
}
response = service.searchanalytics().query(
    siteUrl=SITE_URL, body=request
).execute()

for row in response.get("rows", []):
    q = row["keys"][0]
    print(f"{row['clicks']:>5}  {row['impressions']:>6}  "
          f"{row['ctr']*100:>5.1f}%  pos={row['position']:>5.1f}  {q}")

To cała integracja. Uruchom, a zobaczysz 25 najczęściej klikanych zapytań z ostatnich 28 dni. Dwie uwagi: sc-domain:example.com dotyczy właściwości domenowych (zalecany typ); pełnego URL używaj tylko dla URL-prefix. Dane GSC mają opóźnienie ~2 dni, stąd today - 2.

Macierz zapytanie × strona — ta, która faktycznie napędza decyzje — dodaje drugi wymiar i zwiększa limit wierszy:

request = {
    "startDate": start.isoformat(),
    "endDate": end.isoformat(),
    "dimensions": ["query", "page"],
    "rowLimit": 5000,
    "orderBy": [{"field": "impressions", "descending": True}],
}
response = service.searchanalytics().query(
    siteUrl=SITE_URL, body=request
).execute()

opportunities = []
for row in response.get("rows", []):
    query, page = row["keys"]
    impressions = row["impressions"]
    ctr = row["ctr"]
    position = row["position"]
    # Cells with >500 impressions and CTR below 2% are CTR-leak candidates
    if impressions > 500 and ctr < 0.02 and position < 15:
        opportunities.append((impressions, query, page, position, ctr))

opportunities.sort(reverse=True)
for imp, q, p, pos, ctr in opportunities[:20]:
    print(f"{imp:>6} imp  pos={pos:>4.1f}  ctr={ctr*100:>4.1f}%  {q}  →  {p}")

Filtr na dole (dużo wyświetleń, niski CTR, pozycja < 15) to klasyczna lista kandydatów do przepisywania title-tagów. Już rankujesz — przecieka kliknięcie. Ten sam algorytm płatne narzędzia pokazują jako „ranking opportunities” w sześciu liniach.

Sample output of the query-by-page matrix showing impressions, CTR, position, query and target URL columns
Wynik macierzy zapytanie × URL. Wiersz to przecięcie zapytania i strony. Wiersze z dużą liczbą wyświetleń i niskim CTR to kandydaci do zmiany tytułu.

Co wykresować: cztery wizualizacje warte zachodu

Po zebraniu wierszy pytanie brzmi: co narysować. Większość płatnych narzędzi topi Cię w 40 widgetach; potrzebujesz czterech, by podejmować cotygodniowe decyzje. Zbuduj w tym, co już używasz: Chart.js dla HTML, matplotlib w Jupyterze, natywne wykresy, jeśli zrzucasz do Google Sheets.

  1. Liniowy wykres dziennych kliknięć i wyświetleń, 90 dni. Najważniejszy. Pokazuje, czy ruch rośnie, stoi czy spada. Rozjazd (wyświetlenia w górę, kliknięcia w miejscu) to sygnatura AI Overview.
  2. Pasek top 20 zapytań z kolorem pozycji. Sortowane po kliknięciach. Zieleń dla pozycji 1–5, żółty 6–10, czerwony 11+. Widać, które zapytania wygrywasz, które są zagrożone, które trzeba odświeżyć.
  3. Wykres rozrzutu spadku pozycji. Oś X: pozycja 4 tyg. temu. Oś Y: pozycja dziś. Przekątna = brak zmian. Punkty nad przekątną spadły; pod — wzrosły. Czerwone kropki w prawym górnym rogu to watchlista spadków; workflow w artykule o odświeżaniu treści.
  4. Szacowany wpływ AI Overview. Rysuj wyświetlenia i kliknięcia jako dwie linie, znormalizowane tak, by pokrywały się w dzień 1. Gdy się rozchodzą (wyświetlenia stabilne, kliknięcia spadają), luka to w przybliżeniu kanibalizacja przez AI Overview. Nieidealne, ale kierunkowo przydatne.
Mockup of the four core GSC charts: daily clicks line, top queries bar, position decay scatter, AI Overview impact divergence
Cztery wykresy. Płatne dashboardy mają 40+ widgetów; solo-founderowi te cztery pokrywają ~90% decyzji.

Wzorce automatyzacji: Cron, Slack, Sheets, Django

Ręczne odpytywanie jest OK jednorazowo. Dashboard staje się użyteczny, gdy działa sam. Trzy wzorce automatyzacji, rosnąco wg nakładu:

Wzorzec 1: Cron i alerty Slack. Najtańszy. Codzienny cron odpala skrypt, a jeśli zajdą trzy warunki — spadek kliknięć > 20% tydzień do tygodnia, zapytanie z top 10 wypadło z top 20 lub zaindeksowana strona wypadła z indeksu — wrzuca wiadomość na Slacka. Około 80 linii Pythona z webhookiem. Działa 4 s na VPS za 5 USD. Dashboard robi jedno: krzyczy, gdy coś się zmienia.

import json, os, urllib.request

def post_slack(text):
    payload = {"text": text}
    req = urllib.request.Request(
        os.environ["SLACK_WEBHOOK_URL"],
        data=json.dumps(payload).encode(),
        headers={"Content-Type": "application/json"},
    )
    urllib.request.urlopen(req, timeout=10).read()

# After computing wow_change from two consecutive 7-day GSC pulls:
if wow_change < -0.20:
    post_slack(
        f":warning: GSC clicks dropped {wow_change*100:.0f}% WoW "
        f"({last_week} → {this_week}). Top falling queries: {falling[:3]}"
    )

Wzorzec 2: Zrzut do Google Sheets. Wiersze trafiają do arkusza przez Sheets API lub prostsze gspread. Arkusz staje się dashboardem: tabele przestawne, natywne wykresy, łatwo współdzielić z nietechnicznym co-founderem. Ok. 30 linii ponad pobranie GSC. Minus: odświeżanie zależy od cron’a, a Sheets zamula po ~20 000 wierszy.

Wzorzec 3: Lekki widok Django. Jeden view pobiera dane GSC, cache’uje w Redisie na 6 h i renderuje cztery wykresy Chart.js. Około 200 linii Pythona i HTML. Opłaca się, gdy co-founder chce zerknąć w połowie tygodnia. Cache jest krytyczny; bez niego każde odświeżenie strony wywoła API i wyczerpie limit w dzień premiery.

„Anulowałem Ahrefs za 329 USD/mies. po tym, jak zorientowałem się, że codziennie patrzę tylko na ‚top organic queries’. Napisałem to na API Search Console w jedno popołudnie.”

Motyw regularnie przewija się w wątkach indie-hackerów na HN i zakątkach IndieHackers.

DIY vs SEMrush vs SEOJuice vs Ahrefs vs darmowe UI GSC

Porównanie, którego founderzy naprawdę chcą, to nie płatne narzędzia między sobą, ale: płacić, budować samemu czy żyć z darmowego UI GSC. Tak to wygląda:

OpcjaKoszt mies.Czas setupuUtrzymanieMulti-propertyDane historyczne
Darmowe UI GSC0 USD0 hBrakRęczne przełączanie16 mies., wolny eksport
DIY GSC API + cron + Sheets0–5 USD (VPS)4–8 h~30 min/kwartałProsta pętla16 mies., zapytania w sek.
SEOJuice29–99 USD~10 minBrak (managed)Wbudowane16 mies. z GSC + własna historia crawl’i
SEMrush139–499 USD~30 minBrak (managed)Limity projektów wg planu>2 lata na wyższych planach
Ahrefs129–449 USD~30 minBrak (managed)Limity projektów wg planu>2 lata na wyższych planach

DIY wygrywa kosztem, dorównuje głębokością danych wewnątrz własnej domeny i przegrywa na konkurencję i backlinki. Na wczesnym etapie, gdy pytanie brzmi „co działa u mnie?”, DIY wygrywa. Przy skalowaniu i researchu konkurencji płatne narzędzia zwracają koszt. Strona narzędzi SEOJuice to środek: zarządzana integracja GSC plus crawl, audyt i AI visibility bez enterprise-owego narzutu SEMrush.

Co AI Overview myli w danych GSC

Zapytaj ChatGPT lub Gemini o interpretację GSC, a dostaniesz wiarygodnie brzmiące, lecz błędne odpowiedzi w trzech punktach. Błędy te trafiają do każdego „AI SEO report” na rynku.

Błąd 1: „Position to średnia pozycja, jaką zajmowałeś na to zapytanie.” To średnia najwyższej pozycji, jaką dowolny Twój URL zajął w wyświetleniach, gdy zapytanie wywołało wynik z Twoją stroną. Jeśli dwa URL-e rankują, liczy się wyższy. Dlatego „position” zmienia się, gdy publikujesz nowy artykuł przewyższający stary.

Błąd 2: „CTR liczy się na wyświetlenie.” CTR to kliknięcia ÷ wyświetlenia na poziomie agregacji, który pobierasz. Po samej dacie daje dzienny CTR dla całej witryny; po query+page — CTR per komórka. Liczby nie sumują się między poziomami, bo zmienia się mianownik.

Błąd 3: „Jeśli zapytanie ma wyświetlenia, ale brak kliknięć, strona rankuje słabo.” W erze AI Overview to coraz częściej sygnatura bycia cytowanym w Overview bez kliknięcia. Wyświetlenia zostają, kliknięcia spadają. Strona nie rankuje gorzej; SERP zmienił kształt. Artykuł o cytacjach AI Overview opisuje, co z tym zrobić.

Pułapki przy budowie własnej integracji

Pięć ostrych krawędzi, które ranią debiutantów GSC API. Znając je z góry, oszczędzasz tydzień:

  • Twardy limit 25 000 wierszy na request. Powyżej stronicuj startRow. Biblioteka google-api-python-client nie robi tego automatycznie; pętla, aż przyjdzie < 25 000 wierszy.
  • Klucze konta usługi nie wygasają, ale Google je unieważni po wycieku. Traktuj plik JSON jak hasło DB — sekret manager w produkcyjnym, nigdy w git.
  • Opóźnienie 2 dni dotyczy dnia, nie zapytania. Dzisiejsze dane są puste. Dane sprzed dwóch dni są niemal finalne; wczoraj — częściowe.
  • Właściwości domenowe (sc-domain:) i URL-prefix (https://...) raportują różne liczby. Domenowe agregują subdomeny i protokoły. Jeśli masz obie, zobaczysz częściowo nakładające się dane. Wybierz jedną jako źródło prawdy.
  • Koszyk „anonymized queries” zjada ok. 15–25 % zapytań z ogona. Niskowolumenowe zapytania trafiają do (anonymized) i nie da się ich odzyskać. Analizę top-queries opieraj na nazwanych.

Żadna z nich nie jest blokująca, ale każda kosztowała mnie godzinę. Oficjalna dokumentacja opisuje je wszystkie, tylko nie dość głośno.

FAQ

Jak długo GSC API przechowuje dane historyczne? 16 miesięcy. Potem znikają; brak archiwum. Jeśli chcesz dłuższe trendy, zapisuj okno kroczące do własnej bazy. 365 dni w Postgresie to kilkaset MB na własność.

Czy mogę użyć API do zgłaszania URL-i do indeksu? Nie. Zgłaszanie usunięto w 2020 r. po spamie. Indexing API istnieje, ale obsługuje tylko oferty pracy i livestreamy; użycie do zwykłych treści łamie politykę Google.

Jaka jest różnica między impressions a clicks? Impressions liczą każde wyświetlenie URL-a w SERP, niezależnie od scrollu. Clicks liczą kliknięcia użytkownika. CTR to stosunek. Era AI Overview poszerza lukę, bo użytkownicy widzą odpowiedź w Overview i nie klikają źródeł.

Czy istnieje darmowy tier ponad standardowy limit? Limit jest taki sam dla wszystkich: 1 200 zap./min na endpointy analytics, 2 000/dobę na URL Inspection. Brak płatnej ścieżki; podniesienie limitu można wnioskować w Cloud Console, ale rzadko potrzebne solo.

Czy mogę delegować dostęp bez udostępniania konta Google? Tak, do tego służy konto usługi. Tworzysz jedno na integrację, dajesz Restricted do własności i cofasz bez ruszania własnego loginu.

Jakie języki obsługuje API? Oficjalnie: Python, Node, Java, PHP, Ruby, Go, .NET. Nieoficjalnie: wszystko, co uderzy w REST z Bearer tokenem. JSON wygląda identycznie.

Side-by-side comparison of free GSC UI, DIY GSC API dashboard, SEOJuice, SEMrush, and Ahrefs across cost, setup, maintenance
Pięć opcji dashboardu SEO founder’a — koszt vs. czas setupu. DIY jest darmowe, ale zajmuje godziny inżynierii.

Kiedy DIY przestaje się opłacać

Dashboard DIY zwraca się, dopóki potrzebne dane żyją w Twojej domenie. Gdy pytanie brzmi „dlaczego konkurent mnie wyprzedza?” lub „kto linkuje do nich, a nie do mnie?”, osiągasz sufit GSC. Wtedy płacisz SEMrush/Ahrefs 129–449 USD/mies. za linki i konkurencję lub mniejszemu narzędziu jak SEOJuice za integrację GSC plus crawl, audyt i AI visibility w 15–25 % ceny enterprise suite’u.

Dla większości solo-founderów granica to 500–5 k USD MRR. Poniżej budujesz sam — czas inżyniera tańszy niż abonament, a poznasz dane. Powyżej drogę — Twoje godziny są zbyt cenne na rotację auth i retry limitów. Pomiędzy to rzut monetą zależny od tego, jak bardzo lubisz pisać Python o północy.

Inna ścieżka: zbuduj wersję cron + Slack w ten weekend (6 h z OAuth) i używaj miesiąc. Jeśli patrzysz tylko na alert „top queries dropping”, odkryłeś, że potrzebowałeś jednego widgetu — buduj dalej lub kup. Artykuł o tanich strategiach SEO opisuje budżetowy playbook.

<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [ { "@type": "Question", "name": "How long does the GSC API keep historical data?", "acceptedAnswer": { "@type": "Answer", "text": "16 months. Past that, the data is gone; there is no archive endpoint. If you want longer-range trend data, run a daily cron that snapshots the rolling window into your own storage." } }, { "@type": "Question", "name": "Can I use the GSC API to submit URLs for indexing?", "acceptedAnswer": { "@type": "Answer", "text": "No. URL submission was removed in 2020 after spam abuse. The Indexing API exists but only supports job postings and livestream events; using it for regular content is against Google policy." } }, { "@type": "Question", "name": "What is the difference between impressions and clicks in GSC?", "acceptedAnswer": { "@type": "Answer", "text": "Impressions count every time a URL was shown on a SERP. Clicks count user clicks on the URL. CTR is the ratio. In the AI Overview era the gap is widening because users see the Overview answer and do not click through." } }, { "@type": "Question", "name": "Is there a free tier above the standard GSC API quota?", "acceptedAnswer": { "@type": "Answer", "text": "The quota is the same for everyone: 1,200 requests/min per project on the analytics endpoints, 2,000/day on URL Inspection. There is no paid upgrade path; quota increases can be requested via the Google Cloud Console but are rarely needed for solo-founder workloads." } }, { "@type": "Question", "name": "Can I delegate GSC access without sharing my Google account?", "acceptedAnswer": { "@type": "Answer", "text": "Yes. That is what service accounts are for. Create one per integration, grant it Restricted access to the property, and revoke its access without touching your own login." } }, { "@type": "Question", "name": "What language bindings does the GSC API support?", "acceptedAnswer": { "@type": "Answer", "text": "Officially: Python, Node, Java, PHP, Ruby, Go, .NET. Unofficially: anything that can hit a REST endpoint with a Bearer token. JSON request shapes are identical across languages." } } ] } </script>
SEOJuice
Stay visible everywhere
Get discovered across Google and AI platforms with research-based optimizations.
Works with any CMS
Automated Internal Links
On-Page SEO Optimizations
Get Started Free

no credit card required

More articles

No related articles found.