Google Ads API podporuje 10 000 operací denně na klientský účet v Basic Access a timeout max 1 hodinu na dotaz, oproti 30 minutám CPU a max 50 skriptům pro Google Ads Scripts (oficiální dokumentace kvót API). U sledovaných účtů ve veřejných benchmarcích Google Ads datové týmy, které přecházejí ze Scriptů na API v Pythonu, ušetří 5 až 12 hodin týdně na reportovacích a auditních pipeline a odemknou případy použití nemožné na Scriptech (BigQuery sync, batch mutace 5 000+ entit, obousměrná integrace s CRM).
Tento průvodce je krok za krokem Python setup pro začátečníky. Přesně ten příkaz ke zkopírování, OAuth snippet funkční napoprvé, první GAQL dotaz a veřejný GitHub repozitář k forknutí pro rychlý start. Žádná marketingová teorie, žádné „objevte nekonečné možnosti API" — jen fungující kód. Předpoklady: Python 3.9+, účet Google Ads, 30 minut. Pokud jste již s Google Ads Scripts zběhlí, přečtěte si nejprve náš průvodce 10 Google Ads skriptů ready-to-copy, který pokládá základy automatizace, jež API rozšíří. Náš kalkulátor plýtvání rozpočtem odhaduje EUR spálená/měsíc broad match bez vyloučených slov nebo nadměrným bounce na LP.
Proč Google Ads API, když existují Scripty?
Google Ads Scripts jsou mocné, ale omezené: max 30 minut CPU na spuštění, max 50 aktivních skriptů na účet, JavaScript ES5 (žádné npm balíčky), žádný přístup k externím vědeckým knihovnám (numpy, pandas, scikit-learn). Google Ads API je stupeň výše: Python, Java, Go, .NET nebo Ruby dle výběru, integrace s libovolným datovým stackem (BigQuery, Snowflake, Airflow, dbt), batch operace, async, vertikální i horizontální škálování bez omezení ze strany Googlu.
Kritérium přepnutí je jednoduché. Zůstaňte na Scriptech, pokud: monitorujete 1 účet nebo omezený MCC, vaše automatizace zvládnete za 30 minut runtime, nepotřebujete externí Python knihovny, váš tým nechce udržovat infrastrukturu. Přejděte na API, pokud: spravujete 10+ účtů paralelně, synchronizujete s datovým skladem (BigQuery, Snowflake), integrujete CRM (HubSpot, Salesforce) obousměrně nebo vystavujete Google Ads operace v interním produktu (dashboard, automation tool).
Operační sweet spot: používejte Scripty pro monitoring jednoho účtu a jednoduché automatizace (upozornění na rozpočet, automatická vyloučená slova), přejděte na API pro datové pipeline, multi-account a integraci CRM. U sledovaných účtů ve veřejných benchmarcích Google Ads přibližně 30 až 40 % zralých struktur (>500 tis. EUR/rok výdajů) kombinuje obojí: Scripty pro každodenní taktiku, API pro týdenní strategii a datové synchronizace.
Častá otázka v školení: „mám už 4–5 Scriptů, musím vše migrovat?" Pragmatická odpověď je ne. Migrace na API se vyplatí pouze tehdy, když získáváte kapacitu (multi-account, data warehouse, vědecké knihovny) nebo ztrácíte čas na omezeních Scriptů (timeout 30 min, žádné pandas). Pro mid-size účet se správně fungujícími Scripty je nejméně rizikovou strategií ponechat stávající kód a přidat API pouze pro nové případy použití. Oba pipeline koexistují bez konfliktu: Scripty běží na straně Googlu, vaše API běží na vaší infrastruktuře, neovlivňují se.
Druhý kompromis, na který se často zapomíná, jsou celkové náklady na vlastnictví. Scripty jsou z pohledu infrastruktury zdarma (hostuje Google), ale vyžadují JavaScript v omezeném sandboxu — tedy hodiny vývoje pro obcházení omezení. API vyžaduje Python, infrastrukturu (Cloud Run, Lambda, EC2 nebo jednoduchý cron na VPS), monitoring, správu tajných klíčů a udržování závislostí. Za 12 měsíců stojí Python API setup pro 3–5 skriptů typicky 300 až 1 200 EUR za cloudovou infrastrukturu plus 20 až 60 hodin vývoje/údržby. Nad 10 skriptů nebo 20 spravovaných účtů se ROI jasně překlopí ve prospěch API.
Nastavení prostředí Python: OAuth2, credentials, knihovna
Nastavení obnáší 6 kroků: vytvořit GCP projekt, vygenerovat OAuth2 credentials, získat developer_token Google Ads, nainstalovat knihovnu, vygenerovat refresh_token, otestovat GAQL dotazem. Počítejte celkem 30 minut. Zde je přesný postup.
Krok 1 — GCP projekt a aktivace API
Na console.cloud.google.com vytvořte nový projekt (libovolný název, např. google-ads-api-prod). V APIs and Services > Library vyhledejte „Google Ads API" a klikněte Enable. API je zdarma, ale vyžaduje explicitní aktivaci na projekt GCP.
Krok 2 — OAuth2 credentials (typ Desktop app)
V APIs and Services > Credentials klikněte Create Credentials > OAuth client ID. Typ: Desktop app. Zadejte výstižný název (např. google-ads-api-cli). Stáhněte JSON, uložte si client_id a client_secret. Obě hodnoty budou součástí google-ads.yaml.
Krok 3 — Developer token v Google Ads
V Google Ads, Tools and Settings > API Center. Pokud ještě nemáte, požádejte o developer_token. Počáteční token je v Test módu (15 000 ops/den, pouze testovací účty). Pro přechod na Basic Access (10 000 ops/den, produkční účty) podejte žádost s popisem případu použití — Google odpoví za 1 až 5 pracovních dní. Pro Standard Access (neomezeno) počítejte 2 až 4 týdny revize.
Krok 4 — Instalace knihovny a vygenerování refresh_tokenu
Instalace oficiální knihovny:
# Vyžadován Python 3.9+
pip install google-ads
# Ověřit verzi (24.0.0+ odpovídá API v17)
pip show google-ads
Pro vygenerování refresh_tokenu je nejjednodušší použít oficiální auth skript poskytnutý Googlem:
# Naklonovat oficiální příklady
git clone https://github.com/googleads/google-ads-python.git
cd google-ads-python/examples/authentication
# Spustit generovací skript
python generate_user_credentials.py \
--client_id YOUR_CLIENT_ID \
--client_secret YOUR_CLIENT_SECRET
Skript otevře OAuth stránku ve vašem prohlížeči. Potvrďte přístup ke Google Ads účtu. Skript vypíše refresh_token ve formátu 1//0g...XXXXX. Zkopírujte ho okamžitě, zobrazí se pouze jednou.
Krok 5 — Konfigurace google-ads.yaml
Vytvořte soubor google-ads.yaml v kořenovém adresáři projektu:
# google-ads.yaml — IHNED PŘIDAT DO .gitignore
developer_token: "YOUR_DEVELOPER_TOKEN_22_CHARS"
client_id: "YOUR_CLIENT_ID.apps.googleusercontent.com"
client_secret: "GOCSPX-YOUR_CLIENT_SECRET"
refresh_token: "1//0gYOUR_REFRESH_TOKEN"
login_customer_id: "1234567890" # Nadřazený MCC bez pomlček
use_proto_plus: true
login_customer_id je ID vašeho nadřazeného MCC bez pomlček (např. 123-456-7890 se stane 1234567890). Pod tímto účtem API autentizuje každý dotaz. Pokud dotazujete klientský účet tohoto MCC, zadáte customer_id klientského účtu přímo v dotazu.
Přidejte google-ads.yaml do .gitignore PŘED prvním commitem. Refresh_token uniklý na veřejný GitHub je boty detekován do 30 minut a může být použit k účtování výdajů na váš účet. V produkci načítejte YAML ze secret manageru (AWS Secrets Manager, GCP Secret Manager, Vault) — nikdy jako plain text na serveru.
Krok 6 — Otestovat nastavení jednoduchým dotazem
# test_setup.py
from google.ads.googleads.client import GoogleAdsClient
CUSTOMER_ID = "1112223333" # ID klientského účtu (ne MCC)
def test_connection():
client = GoogleAdsClient.load_from_storage("google-ads.yaml")
ga_service = client.get_service("GoogleAdsService")
query = """
SELECT campaign.id, campaign.name, campaign.status
FROM campaign
LIMIT 5
"""
response = ga_service.search(customer_id=CUSTOMER_ID, query=query)
for row in response:
print(f"{row.campaign.id} | {row.campaign.name} | {row.campaign.status.name}")
if __name__ == "__main__":
test_connection()
Spusťte python test_setup.py. Pokud vidíte 5 názvů kampaní, nastavení je správné. Při chybě INVALID_CUSTOMER_ID ověřte formát (10 číslic bez pomlček). Při chybě NOT_ADS_USER je refresh_token vázán na Google účet bez přístupu k zadanému customer_id.
První GAQL dotaz: výkonnost kampaní
GAQL (Google Ads Query Language) je dotazovací jazyk Google Ads API. Syntaxe blízká SQL, ale se specifiky: žádné explicitní JOIN (zdroje jsou zanořeny), hierarchicky strukturovaná pole (campaign.id, metrics.clicks, segments.date) a DURING pro datové rozsahy místo WHERE date BETWEEN.
Zde je kompletní skript, který stahuje výkonnost ENABLED kampaní za posledních 30 dní s impresemi, kliky, náklady, konverzemi, CTR, CPC, CPA: Náš kalkulátor CPA ve 2 vstupech vrátí hodnotu + medián Francie pro váš vertikál.
# pull_campaign_performance.py
from google.ads.googleads.client import GoogleAdsClient
from google.ads.googleads.errors import GoogleAdsException
CUSTOMER_ID = "1112223333"
def pull_performance(client, customer_id):
ga_service = client.get_service("GoogleAdsService")
query = """
SELECT
campaign.id,
campaign.name,
campaign.status,
metrics.impressions,
metrics.clicks,
metrics.cost_micros,
metrics.conversions,
metrics.conversions_value,
metrics.ctr,
metrics.average_cpc
FROM campaign
WHERE campaign.status = 'ENABLED'
AND segments.date DURING LAST_30_DAYS
ORDER BY metrics.cost_micros DESC
LIMIT 50
"""
try:
response = ga_service.search(customer_id=customer_id, query=query)
results = []
for row in response:
cost_eur = row.metrics.cost_micros / 1_000_000 # micros -> EUR
cpa = cost_eur / row.metrics.conversions if row.metrics.conversions > 0 else None
results.append({
"id": row.campaign.id,
"name": row.campaign.name,
"impressions": row.metrics.impressions,
"clicks": row.metrics.clicks,
"cost_eur": round(cost_eur, 2),
"conversions": row.metrics.conversions,
"ctr_pct": round(row.metrics.ctr * 100, 2),
"cpc_eur": round(row.metrics.average_cpc / 1_000_000, 2),
"cpa_eur": round(cpa, 2) if cpa else None,
})
return results
except GoogleAdsException as ex:
print(f"Request failed: {ex.error.code().name}")
for error in ex.failure.errors:
print(f" - {error.message}")
raise
if __name__ == "__main__":
client = GoogleAdsClient.load_from_storage("google-ads.yaml")
perf = pull_performance(client, CUSTOMER_ID)
for c in perf:
print(f"{c['name'][:40]:40s} | "
f"{c['impressions']:>8,} impr | "
f"{c['clicks']:>5,} kliky | "
f"{c['cost_eur']:>7,.2f} EUR | "
f"{c['conversions']:>5.1f} konv | "
f"CPA: {c['cpa_eur']}")
Tři kritické body tohoto dotazu. Zaprvé: náklady jsou v mikro (1 EUR = 1 000 000 mikro). Vždy dělit 1_000_000 pro získání EUR. Zadruhé: metrics.ctr je float mezi 0 a 1, vynásobte 100 pro procento. Zatřetí: klauzule DURING LAST_30_DAYS je ekvivalentem WHERE segments.date BETWEEN '2026-03-28' AND '2026-04-26', ale mnohem čitelnější. Seznam konstant DURING: TODAY, YESTERDAY, LAST_7_DAYS, LAST_30_DAYS, LAST_90_DAYS, THIS_MONTH, LAST_MONTH atd. (úplný seznam).
Tři další pasti, na které začátečníci v GAQL naráží. *Past 1: žádné SELECT . API vyžaduje explicitní deklaraci každého pole. Vypsání 25 polí ručně je zdlouhavé, ale záměrné — Google chce omezit šířku pásma a donutit inzerenty vědět, co konzumují. Udržování znovupoužitelné Python konstanty CAMPAIGN_FIELDS = [...] ušetří přepisování seznamu v každém skriptu. Past 2: segments.date vždy způsobuje row-fanning. Dotaz bez segments.date agreguje za celé DURING období; s segments.date získáte řádek na kampaň na den, tedy 30× více řádků. Vědomě vyberte podle potřeby (souhrny období vs. časové řady). Past 3: ORDER BY je povinné pro konzistentní stránkování. API automaticky stránkuje nad 10 000 řádků; bez explicitního ORDER BY není pořadí stránek zaručeno a při batch zpracování riskujete přeskočení entit.
Pro testování dalších GAQL dotazů interaktivně bez Pythonu poskytuje Google GAQL Query Builder v oficiální dokumentaci — nejrychlejší způsob iterace nad strukturou dotazu před jeho zakódováním. Praktický tip: prototypujte dotaz v query builderu, zkopírujte do Python skriptu a teprve pak přidejte mapování na sloupce BigQuery nebo pandas. Vyhnete se přepisování dotazu třikrát při ladění kvůli zapomenutému poli.
Mutace: vytvoření, aktualizace, pozastavení kampaně
Mutace jsou operace zápisu API: vytvoření kampaně, změna rozpočtu, pozastavení klíčového slova, přidání vyloučeného slova. Procházejí dedikovanými službami (CampaignService, CampaignBudgetService, KeywordPlanService atd.) a používají vzor operation > mutation > response.
Zde je skript, který pozastaví kampaň podle jejího ID:
# pause_campaign.py
from google.ads.googleads.client import GoogleAdsClient
from google.ads.googleads.errors import GoogleAdsException
CUSTOMER_ID = "1112223333"
CAMPAIGN_ID = "111222333"
def pause_campaign(client, customer_id, campaign_id):
campaign_service = client.get_service("CampaignService")
# Sestavení resource_name (povinný formát)
resource_name = campaign_service.campaign_path(customer_id, campaign_id)
# Operace: update
campaign_operation = client.get_type("CampaignOperation")
campaign = campaign_operation.update
campaign.resource_name = resource_name
campaign.status = client.enums.CampaignStatusEnum.PAUSED
# Field mask (specifikuje, co aktualizujeme)
client.copy_from(
campaign_operation.update_mask,
protobuf_helpers.field_mask(None, campaign._pb),
)
try:
response = campaign_service.mutate_campaigns(
customer_id=customer_id,
operations=[campaign_operation],
)
print(f"Paused campaign: {response.results[0].resource_name}")
except GoogleAdsException as ex:
for error in ex.failure.errors:
print(f"Error: {error.message}")
if error.location:
for field in error.location.field_path_elements:
print(f" Field: {field.field_name}")
raise
if __name__ == "__main__":
from google.api_core import protobuf_helpers
client = GoogleAdsClient.load_from_storage("google-ads.yaml")
pause_campaign(client, CUSTOMER_ID, CAMPAIGN_ID)
Kritický vzor pro VŠECHNY mutace: resource_name + update_mask. resource_name identifikuje entitu (customers/{customer_id}/campaigns/{campaign_id}), update_mask specifikuje, která pole měníme (bez něj API vrátí INVALID_FIELD_MASK). protobuf_helpers.field_mask(None, campaign._pb) automaticky vygeneruje masku z modifikovaných polí.
Pro vytvoření nové kampaně (Search Standard, denní rozpočet 100 EUR, Manual CPC):
# create_search_campaign.py
from google.ads.googleads.client import GoogleAdsClient
from google.ads.googleads.errors import GoogleAdsException
import uuid
CUSTOMER_ID = "1112223333"
def create_campaign_budget(client, customer_id, daily_budget_eur):
budget_service = client.get_service("CampaignBudgetService")
operation = client.get_type("CampaignBudgetOperation")
budget = operation.create
budget.name = f"Budget {uuid.uuid4().hex[:8]}"
budget.amount_micros = int(daily_budget_eur * 1_000_000)
budget.delivery_method = client.enums.BudgetDeliveryMethodEnum.STANDARD
response = budget_service.mutate_campaign_budgets(
customer_id=customer_id, operations=[operation]
)
return response.results[0].resource_name
def create_search_campaign(client, customer_id, name, budget_resource):
campaign_service = client.get_service("CampaignService")
operation = client.get_type("CampaignOperation")
campaign = operation.create
campaign.name = name
campaign.advertising_channel_type = client.enums.AdvertisingChannelTypeEnum.SEARCH
campaign.status = client.enums.CampaignStatusEnum.PAUSED # vytvořit jako PAUSED, aktivovat po kontrole
campaign.manual_cpc.enhanced_cpc_enabled = False
campaign.campaign_budget = budget_resource
# Nastavení sítě
campaign.network_settings.target_google_search = True
campaign.network_settings.target_search_network = True
campaign.network_settings.target_content_network = False
campaign.network_settings.target_partner_search_network = False
response = campaign_service.mutate_campaigns(
customer_id=customer_id, operations=[operation]
)
return response.results[0].resource_name
if __name__ == "__main__":
client = GoogleAdsClient.load_from_storage("google-ads.yaml")
budget_rn = create_campaign_budget(client, CUSTOMER_ID, daily_budget_eur=100)
print(f"Budget created: {budget_rn}")
campaign_rn = create_search_campaign(
client, CUSTOMER_ID, "Test API Campaign", budget_rn
)
print(f"Campaign created (PAUSED): {campaign_rn}")
Osvědčené postupy pro mutace:
- Vždy vytvářet jako PAUSED na začátku, aktivovat ručně po kontrole. Kampaň omylem vytvořená jako ENABLED může spotřebovat rozpočet za několik hodin.
- Logovat resource_name vrácený API pro sledovatelnost.
- Systematicky zabalovat do try/except GoogleAdsException (viz sekce retry).
- Testovat na testovacím účtu před zásahem do produkce. API nenabízí nativní dry-run mód (na rozdíl od Scriptů).
Zpracování chyb a retry logika v produkci
Google Ads API může vracet 3 kategorie chyb: přechodné (RESOURCE_EXHAUSTED, DEADLINE_EXCEEDED, UNAVAILABLE) odůvodňující retry s backoffem, chyby klienta (INVALID_ARGUMENT, NOT_FOUND, PERMISSION_DENIED), které nikdy neuspějí při opakování, a rate limit (TOO_MANY_REQUESTS) vyžadující čekání na další okno.
Zde je wrapper exponenciálního retry ke zkopírování do všech produkčních skriptů:
# retry_helpers.py
import time
from functools import wraps
from google.ads.googleads.errors import GoogleAdsException
from google.api_core.exceptions import (
DeadlineExceeded, ServiceUnavailable, ResourceExhausted
)
RETRYABLE_ERRORS = (
DeadlineExceeded,
ServiceUnavailable,
ResourceExhausted,
)
def with_retry(max_retries=3, base_delay=2.0, max_delay=60.0):
"""
Decorator, který automaticky opakuje s exponenciálním backoffem
při přechodných chybách Google Ads API.
"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(max_retries + 1):
try:
return func(*args, **kwargs)
except RETRYABLE_ERRORS as e:
if attempt == max_retries:
print(f"[RETRY] Max retries reached: {e}")
raise
delay = min(base_delay * (2 ** attempt), max_delay)
print(f"[RETRY] Attempt {attempt + 1}/{max_retries} "
f"failed: {type(e).__name__}. Retry in {delay}s...")
time.sleep(delay)
except GoogleAdsException as e:
# Kontrola, zda je chyba opakovatelná (zejm. rate limit)
is_retryable = any(
err.error_code.quota_error or
err.error_code.internal_error
for err in e.failure.errors
)
if is_retryable and attempt < max_retries:
delay = min(base_delay * (2 ** attempt), max_delay)
print(f"[RETRY] GoogleAdsException retryable. "
f"Retry in {delay}s...")
time.sleep(delay)
else:
# Neopakovatelná chyba klienta
for error in e.failure.errors:
print(f"[ERROR] {error.error_code}: {error.message}")
raise
return None
return wrapper
return decorator
# Použití
@with_retry(max_retries=3, base_delay=2.0)
def pull_performance_safe(client, customer_id):
ga_service = client.get_service("GoogleAdsService")
query = "SELECT campaign.id, campaign.name FROM campaign LIMIT 100"
return list(ga_service.search(customer_id=customer_id, query=query))
Vzor: exponenciální backoff (prodleva se při každém retry zdvojí, zastropuje na 60 sekundách) + klasifikace chyb (opakovatelné vs. neopakovatelné). Nikdy neopakovat při INVALID_ARGUMENT — jde o chybu ve vašem kódu, ne o síťový problém. Nikdy neopakovat donekonečna — max 3 až 5 retries, jinak maskujete strukturální problém (revokovaný token, trvale vyčerpaná kvóta).
Pro strukturované logování použijte standardní Python logging s JSON formátem pro ingestion do observability stacku (Datadog, Grafana Loki):
import logging
import json
class JsonFormatter(logging.Formatter):
def format(self, record):
log_obj = {
"ts": self.formatTime(record),
"level": record.levelname,
"msg": record.getMessage(),
"module": record.module,
}
if record.exc_info:
log_obj["exc"] = self.formatException(record.exc_info)
return json.dumps(log_obj)
logger = logging.getLogger("google_ads_api")
handler = logging.StreamHandler()
handler.setFormatter(JsonFormatter())
logger.addHandler(handler)
logger.setLevel(logging.INFO)
# Použití
logger.info("Pulled 247 campaigns", extra={"customer_id": CUSTOMER_ID})
U sledovaných účtů ve veřejných benchmarcích Google Ads API pipeline bez retry logiky selhávají průměrně 2 až 4× za měsíc kvůli přechodným síťovým chybám nebo rate limitu, oproti 0 až 1× za čtvrtletí s retry wrapperem + backoffem. To je investice 30 řádků kódu, která posune skript z „demo" na „produkčně připravený".
OAuth refresh flow: na co se zapomíná v produkci
refresh_token Google Ads nevypráší, pokud je použit alespoň jednou za 6 měsíců. Může však být revokován v několika případech, které je třeba znát. První případ: uživatel Google, který token vygeneroval, změní heslo nebo MFA — všechny refresh_tokeny vázané na tento účet se zneplatní. Druhý případ: Google detekuje podezřelé chování (token použitý z 30 různých IP za 1 hodinu), automaticky revokuje a zašle bezpečnostní email. Třetí případ: překročení limitu 50 simultánně aktivních refresh_tokenů na OAuth klienta spustí tiché FIFO zneplatnění nejstarších. Proto doporučujeme dedikovaný technický účet pro API (nikdy osobní Google účet zaměstnance) se stabilním heslem a MFA hardware klíčem.
Vzor retry při auth chybě musí být odlišný od přechodného síťového retry. Pokud obdržíte UNAUTHENTICATED nebo PERMISSION_DENIED vázané na token, NIKDY neopakujte s backoffem — token neobživne. Místo toho spusťte upozornění (PagerDuty, Slack ops) a nechte člověka vygenerovat nový refresh_token skriptem generate_user_credentials.py. Záměna těchto dvou případů může stát hodiny ladění a ztracené konverze. Pro omezení překvapení monitorujte zdraví tokenu jednoduchým cronem: minimalistický GAQL dotaz (SELECT customer.id FROM customer LIMIT 1) každých 6 hodin, upozornění při selhání auth.
Rate limiting: pochopení kvót v praxi
API kvóty jsou strukturovány na dvou úrovních: operace za den (Test 15 000, Basic 10 000 na klientský účet, Standard oficálně neomezeno, ale throttlování od cca 1 milionu/den) a dotazy za sekundu (soft limit kolem 50 RPS udržovaných na OAuth klienta, pod touto hodnotou API vrací bez chyby). Jedna operace = jeden mutovaný řádek, jeden get nebo jedna stránka výsledků GAQL. GAQL dotaz vracející 5 000 řádků se počítá jako 1 operace, ne jako 5 000.
Nejčastější past v produkci: batch mutace překračující 5 000 operací v jediném volání. API pak vrátí RESOURCE_EXHAUSTED ne kvůli denní kvótě, ale kvůli per-call limitu 5 000 operací. Správný vzor je rozdělení listů do chunků: pokud máte 12 000 vyloučených klíčových slov k přidání, proveďte 3 volání po 4 000 klíčových slovech místo jednoho s 12 000. Chunking přidá 5 řádků kódu a zabrání 90 % chyb při bulk operacích.
# Chunking vzor pro batch mutace
def chunked(iterable, size=4000):
for i in range(0, len(iterable), size):
yield iterable[i:i + size]
for chunk in chunked(all_operations, size=4000):
response = service.mutate_negatives(
customer_id=customer_id, operations=chunk
)
print(f"Chunk processed: {len(response.results)} mutations")
Pro noční batch pipeline přidejte time.sleep(0.5) mezi chunky pro vyhlazení zátěže bez degradace celkového throughputs. U sledovaných účtů ve veřejných benchmarcích Google Ads batch 50 000 mutací v chuncích po 4 000 + sleep 500 ms trvá přibližně 8–10 minut oproti 4–5 minutám v chuncích po 4 000 bez sleep — ale s mírou selhání dělenou 5. Kompromis čas/spolehlivost za sleep rozhodně stojí.
6 Python skriptů připravených k forknutí
Pro urychlení startu publikujeme veřejný GitHub repozitář github.com/steerads/google-ads-python-starter s 6 zdokumentovanými Python skripty připravenými k forknutí. Každý skript je autonomní, konfigurovaný přes env proměnné a obsahuje retry logiku. Zde je seznam s ukázkovým snippetem pro každý.
Skript 1 — Pull výkonnosti kampaní LAST_30_DAYS
Stahuje kompletní KPI (imprese, kliky, náklady, konverze, ROAS) ENABLED kampaní, exportuje do CSV nebo ukládá do BigQuery. Frekvence: denně nebo hodinově. Viz kompletní snippet v sekci 3.
Skript 2 — Hromadná aktualizace rozpočtu kampaní
Mění denní rozpočty N kampaní v jediné batch operaci. Užitečné pro měsíční rebalancing rozpočtu nebo automatické sezónní úpravy.
# bulk_update_budgets.py
def bulk_update_budgets(client, customer_id, updates):
"""
updates = [{"budget_id": "111", "new_amount_eur": 150}, ...]
"""
service = client.get_service("CampaignBudgetService")
operations = []
for u in updates:
op = client.get_type("CampaignBudgetOperation")
budget = op.update
budget.resource_name = service.campaign_budget_path(
customer_id, u["budget_id"]
)
budget.amount_micros = int(u["new_amount_eur"] * 1_000_000)
client.copy_from(
op.update_mask,
protobuf_helpers.field_mask(None, budget._pb),
)
operations.append(op)
response = service.mutate_campaign_budgets(
customer_id=customer_id, operations=operations
)
return [r.resource_name for r in response.results]
Skript 3 — Přidání vyloučených klíčových slov ze search query reportu
Stahuje Search Term Performance Report za 30 dní, identifikuje dotazy s 0 konverzemi a více než 15 kliky, přidává je jako vyloučená slova na úrovni kampaně. Ekvivalent skriptu 2 z našeho průvodce 10 Scripts ready-to-copy, ale přes API pro zpracování 100+ kampaní v jediném spuštění.
Skript 4 — Pozastavení podvýkonných klíčových slov (CTR + CPA)
Identifikuje klíčová slova s CTR pod 1 % A CPA nad 2× cílovém CPA za 30 dní, automaticky je pozastaví s logem před akcí. Multidimenzionální kritérium nemožné na Scriptech (kde je nutné iterovat přes AdsApp.keywords()), v GAQL triviální.
Skript 5 — Export reportu do BigQuery (data warehousing)
Stahuje agregované metriky, transformuje přes pandas, načítá do BigQuery pomocí google-cloud-bigquery. To je případ použití, kde API předčí Scripty: připojit Scripty k BigQuery správně je nemožné, zatímco v Pythonu je to 10 řádků.
# bigquery_export.py
from google.cloud import bigquery
import pandas as pd
def export_to_bigquery(client, customer_id, dataset_id, table_id):
# 1. Pull GAQL dat
perf = pull_performance(client, customer_id)
df = pd.DataFrame(perf)
df["snapshot_date"] = pd.Timestamp.today().normalize()
# 2. BigQuery klient
bq = bigquery.Client()
table_ref = f"{bq.project}.{dataset_id}.{table_id}"
# 3. Načtení s append
job_config = bigquery.LoadJobConfig(
write_disposition=bigquery.WriteDisposition.WRITE_APPEND,
autodetect=True,
)
job = bq.load_table_from_dataframe(df, table_ref, job_config=job_config)
job.result() # čekat na dokončení
print(f"Loaded {len(df)} rows to {table_ref}")
Skript 6 — Denní monitoring se Slack upozorněními
Kombinuje pull výkonnosti + kontrolu anomálií (výdaje, CPA, konverze) + push do Slacku přes webhook při detekci anomálie. Průmyslový ekvivalent cron jobu denního monitoringu.
# daily_monitoring.py
import requests
SLACK_WEBHOOK = "https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
def detect_anomalies(perf):
alerts = []
for c in perf:
# Výdaje > 2× průměr 7 dní
if c.get("cost_eur", 0) > c.get("avg_cost_7d", 0) * 2:
alerts.append(f"Výdaje +100%: {c['name']}")
# CPA > 3× cíl
if c.get("cpa_eur") and c.get("target_cpa") and \
c["cpa_eur"] > c["target_cpa"] * 3:
alerts.append(f"CPA 3× cíl: {c['name']}")
return alerts
def send_slack(alerts):
if not alerts:
return
msg = "Google Ads anomalie detekovány:\n" + "\n".join(f"- {a}" for a in alerts)
requests.post(SLACK_WEBHOOK, json={"text": msg})
if __name__ == "__main__":
client = GoogleAdsClient.load_from_storage("google-ads.yaml")
perf = pull_performance(client, CUSTOMER_ID)
alerts = detect_anomalies(perf)
send_slack(alerts)
Repozitář github.com/steerads/google-ads-python-starter obsahuje pro každý skript: kompletní zdokumentovaný kód, README s krok za krokem setupem, soubor .env.example pro proměnné a requirements.txt s pevně danými verzemi pro reprodukovatelnost. Pro cross-platform automatizaci viz také náš průvodce n8n Google Ads automation flows a náš průvodce MCP Google Ads + Claude Desktop pro řízení Google Ads konverzačně z Claude.
Kdy přejít ze Scriptů na API
Přechod ze Scriptů na API není systematický upgrade — je to rozhodnutí o kompromisu. Zde je 5 konkrétních spouštěčů sledovaných ve veřejných benchmarcích při auditech.
Spouštěč 1: multi-account (10+ účtů k paralelnímu řízení). Scripty jsou ze své podstaty mono-account (jeden skript vázaný na účet nebo MCC). Nad 10 účtů k synchronizaci se Python API se smyčkou for na seznamu customer_ids stává mnohem lépe udržovatelným.
Spouštěč 2: data warehousing. Pokud chcete ukládat metriky do BigQuery, Snowflake, Redshift, je API povinné. Scripty UrlFetchApp technicky mohou volat REST API, ale autentizace GCP, batching, ETL s pandas — to vyžaduje Python.
Spouštěč 3: obousměrná integrace CRM. Pro push offline konverzí ze Salesforce/HubSpotu podporuje Google Ads API OfflineUserDataJobService pro zabezpečený batch upload. Viz náš průvodce conversion tracking Google Ads pro funkční rámec.
Spouštěč 4: ML / pokročilé statistické potřeby. Statistická detekce anomálií (ARIMA, Prophet), segmentace klíčových slov (clustering), prognózování výdajů — všechny tyto úkoly vyžadují numpy/pandas/scikit-learn, nemožné ve Scriptech.
Spouštěč 5: interní produkt. Vytváříte dashboard nebo interní nástroj zobrazující/manipulující data Google Ads. Nutně API — Scripty nemohou vystavit UI ani odpovídat na HTTP dotaz.
Pro opačných 5 případů (jeden účet, jednoduché monitorování, žádné datové potřeby, netechnický tým, omezená infrastruktura) zůstávají Scripty lepší z hlediska nákladů/údržby. Náš průvodce Microsoft Ads Scripts pokrývá ekvivalent na straně Microsoftu.
Pro účty, které chtějí průmyslovou automatizaci bez psaní vlastního stacku, náš modul Auto-optimalizace pokrývá ekvivalent 6 výše uvedených skriptů v managed módu: pull výkonnosti multi-account, detekce anomálií, Slack upozornění, BigQuery sync — bez jediného řádku Pythonu k údržbě. Viz také náš checklist auditu Google Ads pro základ auditu, který musí předcházet každé automatizaci, a náš srovnání Zapier vs Make pro doplňkové no-code automatizace.
Časté chyby při začátcích s API
Pět opakujících se chyb zpomaluje začátečníky v Pythonu na Google Ads API. Každá stojí průměrně několik hodin zbytečného ladění, pokud znáte past předem. Zde je seznam s diagnózou a přímou opravou.
1. Záměna customer_id a login_customer_id. Diagnóza: skript vrátí INVALID_CUSTOMER_ID nebo NOT_ADS_USER, přestože vše vypadá správně nakonfigurované. Oprava: login_customer_id (v YAML) = ID nadřazeného MCC, pod kterým se API autentizuje, bez pomlček. customer_id (v dotazu) = ID klientského účtu, který chcete dotazovat, bez pomlček. Pokud dotazujete přímo účet, který není pod MCC, zadejte jeho ID na obě místa. Vždy odstraňujte pomlčky formátu 123-456-7890 -> 1234567890.
2. Zapomenutí update_mask u mutací. Diagnóza: mutace selže s MISSING_REQUIRED_FIELD: update_mask nebo všechna pole entity jsou nahrazena výchozími hodnotami (katastrofa v produkci). Oprava: pro každou operaci update vygenerujte masku přes protobuf_helpers.field_mask(None, entity._pb) po nastavení polí. Maska říká API, která pole měníte; bez ní API buď odmítne, nebo interpretuje jako „všechna pole jsou na výchozí hodnotě" a vše vynuluje.
3. Individuální pull ve smyčce místo batch. Diagnóza: skript stahující 500 kampaní trvá 25 minut místo 30 sekund. Oprava: NIKDY nepoužívat for campaign_id in ids: ga_service.search(...) s jedním dotazem na kampaň. Místo toho jeden GAQL dotaz filtrující WHERE campaign.id IN (...) nebo stažení všeho a filtrování na straně Pythonu. API není penalizováno za velikost dotazu, je za počet volání.
4. Testování přímo v produkci bez testovacího účtu. Diagnóza: chyba zaokrouhlení v kódu mutace rozpočtu omylem sníží všechny rozpočty na 1 EUR. Produkce se zhroutí. Oprava: vytvořte testovací Google Ads účet (zdarma, bez přidružené platební karty) pro všechny vývojové mutace. Developer_token Test pokrývá pouze testovací účty — což je vítaná neúmyslná ochrana. Přepněte na Basic Access až po validaci kódu v sandboxu na 2–3 skutečných případech použití.
5. Ignorování stránkování GAQL nad 10 000 řádků. Diagnóza: skript stahující klíčová slova velkého účtu selže nad 10 000 řádků nebo vrátí neúplné výsledky bez chyby. Oprava: používejte ga_service.search_stream(...), který automaticky stránkuje bez načítání celého výsledku do paměti. Pro stahování 50 000+ řádků je povinné — search() načte vše do paměti a selže na strojích s malou RAM.
Pro oficiální dokumentaci viz portál Google Ads API a oficiální repozitář google-ads-python, který obsahuje desítky příkladů udržovaných Googlem.
Zdroje
Oficiální zdroje použité v tomto průvodci:
FAQ
Je potřeba developer token pro použití Google Ads API?
Ano, je povinný. Developer token je vázán na MCC (manager) účet a získá se přes Tools and Settings > API Center v Google Ads. Počáteční token začíná v Test módu (limit 15 000 operací/den, pouze testovací účty), pak Basic Access (10 000 operací/den, produkční účty) na vyžádání, pak Standard Access (neomezeno) po revizi Googlem. Počítejte 1 až 5 pracovních dní pro Basic, 2 až 4 týdny pro Standard s dokumentací vašeho případu použití. Pro začátek token Test plně postačuje: testování OAuth, psaní prvních GAQL dotazů, ladění mutací na testovacím účtu. Přechod na Basic nastane až po validaci kódu v sandboxu.
Jaký je rozdíl mezi google-ads-python (oficiální) a googleads (legacy)?
google-ads-python je moderní oficiální knihovna konzumující REST/gRPC API v17+ (verze 2024–2026). googleads byla legacy knihovna konzumující SOAP API v201809 (deprecated od roku 2022, zcela vypnuta koncem roku 2023). Pokud narazíte na kód s googleads nebo AdWords API na fórech, je zastaralý. Pro rok 2026 používejte VÝHRADNĚ google-ads-python (pip install google-ads), minimálně verzi 24.0.0 odpovídající API v17. Knihovna vystavuje klienta GoogleAdsClient inicializovaného z YAML nebo env vars se typovanými službami (CampaignService, KeywordService, GoogleAdsService pro GAQL dotazy). Oficiální dokumentace na developers.google.com/google-ads/api/docs/client-libs/python.
Kolik GAQL dotazů za sekundu API zvládne?
Kvóty závisí na úrovni vašeho developer tokenu. Test = 15 000 operací/den celkem, Basic = 10 000 operací/den na klientský účet, Standard = žádná oficiální kvóta, ale Google throttluje při zneužití. Jedna operace = jeden GAQL dotaz nebo jedna mutace. U sledovaných účtů ve veřejných benchmarcích Google Ads dominuje vzor 200 až 800 dotazů/den pro skript denního monitoringu na mid-size účtu. Hodinový rate limit je max 10 000 dotazů/hodinu na OAuth klienta. Nad touto hodnotou API vrátí RESOURCE_EXHAUSTED, který je nutné ošetřit exponenciálním backoffem (viz sekce retry logika). Pro skript vyžadující 5 000+ mutací plánujte batch processing se sleep mezi batchy.
Dokáže API spravovat Smart Bidding a Performance Max?
Ano, API vystavuje všechny funkce Google Ads včetně nejnovějších (Performance Max, Smart Bidding, Demand Gen). Pro Performance Max pracujete s CampaignService (campaignType=PERFORMANCE_MAX), AssetGroupService (skupiny assets PMax) a ConversionGoalService. Pro Smart Bidding jsou to bidding_strategy fields kampaní (TARGET_CPA, TARGET_ROAS, MAXIMIZE_CONVERSIONS). Omezení: vytvoření PMax kampaně přes API vyžaduje všechny assets zároveň (obrázky, headlines, popisy, sitelinky), což kód komplikuje oproti vytváření Search kampaní. Pro začátek preferujte tvorbu/úpravu Search nebo Shopping kampaní a na PMax přejděte až po stabilizaci pipeline. Viz náš průvodce Performance Max pro strategii asset group.
Jak zabezpečit OAuth credentials v produkci?
Tři principy: NIKDY necommitovat google-ads.yaml ani refresh_tokeny do Gitu (přidejte je do .gitignore), používejte secret managery (AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault) pro produkční uložení a otáčejte refresh_tokeny periodicky (doporučeno max 90 dní). Pro lokální dev setup je YAML v home directory OK. Pro produkci načítejte YAML ze secret manageru při startu aplikace. developer_token, client_id, client_secret mohou být v env vars; refresh_token musí být v přísném secret manageru. Pokud refresh_token unikne (náhodný commit na GitHub), okamžitě ho zrušte přes Google Cloud Console > APIs and Services > Credentials, vygenerujte nový a auditujte API logy pro detekci případných škodlivých volání.