Google Ads API: Einrichtung, Authentifizierung, Lese- und Schreiboperationen
Eine technische Anleitung für den programmatischen Zugriff auf Google Ads – von der Architektur bis zum ersten API-Aufruf. Behandelt MCC-Konfiguration, OAuth 2.0, Developer-Token-Zugriffsstufen, die google-ads-Python-Bibliothek, GAQL-Leseabfragen und das validate_only-Schreibmuster.
Aktualisierung (Oktober 2026): Google hat Developer-Tokens am 9. September 2026 abgeschafft. API-Zugriffsstufen werden jetzt pro Google-Cloud-Projekt zugewiesen und auf der Übersichtsseite der Google Ads API in der Cloud Console verwaltet. Der Header developer-token ist optional und wird ignoriert, und das API Center bearbeitet keine Registrierungen oder Zugriffsänderungen mehr. Laut Google funktioniert bestehender Code weiterhin. Die folgenden Schritte zu Developer-Tokens und API Center beschreiben die Einrichtung zum Veröffentlichungszeitpunkt im Juni 2026. Die aktuelle Einrichtung beschreibt unser Folgebeitrag Google Ads API-Zugriff 2026: Cloud-Projekte ersetzen Developer Tokens.
Architektur
Drei separate Entitäten sind erforderlich, bevor ein einzelner API-Aufruf funktioniert:
| Entität | Zweck | Beispiel |
|---|---|---|
| Manager-Konto (MCC) | Stellt den Developer-Token aus | login_customer_id |
| Google-Cloud-Projekt | OAuth 2.0-Client für die Authentifizierung | Client-ID + Client-Secret |
| Google-Ads-Konto | Ziel aller API-Operationen | customer_id |
Es handelt sich nicht um dasselbe Konto. Ein MCC kann einen Developer-Token besitzen, ohne das Zielkonto zu besitzen – es muss lediglich als Manager verknüpft sein. Das Google-Cloud-Projekt kann unter einer anderen Google-Identität als das MCC laufen. Das Zielkonto ist das Werbetreibendenkonto, in dem die Kampagnen liegen.
Diese Trennung ist wichtig, weil das API Center (wo Developer-Token bereitgestellt werden) nur innerhalb von Manager-Konten verfügbar ist. Ein eigenständiges Google-Ads-Konto kann nicht auf das API Center zugreifen, selbst wenn es über administrative Nutzer verfügt.
Der API-Aufruf-Header setzt diese drei Identitäten plus ein OAuth-Bearer-Token zusammen:
developer-token: <aus dem MCC API Center>
login-customer-id: <numerische MCC-ID, ohne Bindestriche>
customer-id: <numerische ID des Zielkontos>
Authorization: Bearer <OAuth 2.0 Access Token>
Voraussetzungen
- Ein Google-Ads-Manager-Konto mit abgeschlossener Einrichtung
- Das Zielwerbekonto ist mit dem Manager-Konto verknüpft und die Verknüpfung wurde akzeptiert
- Ein Google-Cloud-Projekt mit aktivierter Google Ads API
- Python 3.9+ mit der
google-ads-Bibliothek (pip install google-ads) - Ein Browser für den einmaligen OAuth-Zustimmungsablauf
Schritt 1: Manager-Konto und Developer-Token
Das API Center befindet sich unter Tools & Settings → Setup → API Center innerhalb eines Manager-Kontos. Wenn das API Center fehlt, ist das Konto entweder kein Manager-Konto oder seine Einrichtung ist unvollständig.
Im API Center einen Developer-Token beantragen. Den Kontotyp auf Advertiser (nicht Agency oder Third-Party) setzen, wenn der Token für die eigenen Konten bestimmt ist. Der Token wird sofort auf der Stufe Test Access ausgestellt.
Test Access erlaubt:
- Leseoperationen nur für Testkonten
- Schreiboperationen nur für Testkonten
- Keine Lese- oder Schreiboperationen für Produktionskonten
Anfragen an Produktionskonten mit Test Access schlagen mit DEVELOPER_TOKEN_NOT_APPROVED fehl („The developer token is only approved for use with test accounts“). Seit der Abschaffung im September 2026 geben aktuelle API-Versionen stattdessen CLOUD_PROJECT_NOT_APPROVED_FOR_PRODUCTION zurück (ACTION_NOT_PERMITTED in v24 und früher).
Antrag auf Basic Access
Um auf Produktionskonten zugreifen zu können, muss Basic Access über dieselbe Seite des API Center beantragt werden. Das Antragsformular stellt 12 Fragen. Für die interne Nutzung auf eigenen Konten lauten die relevanten Antworten:
| Frage | Antwort |
|---|---|
| Q4: Beziehung zu einem Google-Vertreter | Nein |
| Q6: Geschäftsmodell | Eigenen Anwendungsfall beschreiben (E-Commerce, Lead-Generierung, interne Berichterstellung) |
| Q8: Wer wird Zugriff haben | Interne Nutzer – nur Mitarbeiter |
| Q9: Von Drittanbietern entwickeltes Tool | Nein (eigene Skripte/Agenten) |
| Q10: Conversion Tracking & Remarketing API | Nein (es sei denn, sie wird tatsächlich genutzt) |
| Q11: Kampagnentypen | Search, Performance Max, Shopping (je nach Anwendungsfall) |
| Q12: Fähigkeiten | Kampagnenerstellung, Kampagnenverwaltung, Berichterstellung |
Für Q7 ist ein Design-Dokument (PDF) erforderlich. Es sollte die API-Architektur, den Authentifizierungsablauf, die Strategie zur Einhaltung von Aufruflimits, die Fehlerbehandlung und den rein internen Anwendungsfall beschreiben. Das Dokument sachlich halten – das Compliance-Team prüft auf Konsistenz mit dem deklarierten Anwendungsfall.
Bearbeitungszeit Stand Juni 2026: etwa 3 Werktage, mit einem Hinweis auf ein überdurchschnittlich hohes Antragsvolumen.
Schritt 2: OAuth 2.0
Google-Cloud-Projekt einrichten
In der Google Cloud Console unter dem entsprechenden Projekt:
- Die Google Ads API aktivieren (APIs & Services → Bibliothek)
- Den OAuth-Zustimmungsbildschirm konfigurieren:
- Nutzertyp: Internal (nur Nutzer der eigenen Google-Workspace-Organisation können den Zugriff autorisieren – umgeht die externe App-Verifizierung)
- App-Name, Support-E-Mail, E-Mail-Adresse für den Entwicklerkontakt
- Den Scope unter Data Access hinzufügen:
https://www.googleapis.com/auth/adwords - Eine OAuth-Client-ID erstellen:
- Anwendungstyp: Desktop app
- Die JSON-Datei mit dem Client-Secret herunterladen
Der Desktop-App-Typ verwendet http://localhost als Weiterleitungs-URI. Das ist korrekt – der OAuth-Flow öffnet einen Browser, Google leitet mit dem Autorisierungscode an localhost weiter, und ein lokaler HTTP-Server fängt ihn ab.
Refresh-Token erzeugen
Ein minimales Python-Skript (es prüft weder den zurückgegebenen state-Parameter noch setzt es Dateiberechtigungen für die Token-Datei; ergänzen Sie beides, bevor Sie es über einen einmaligen lokalen Lauf hinaus verwenden), das einen lokalen HTTP-Server auf 127.0.0.1:0 (zufälliger Port) startet, die Autorisierungs-URL ausgibt, auf eine Anfrage wartet, den code-Parameter extrahiert und gegen Tokens eintauscht:
from pathlib import Path
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import urlparse, parse_qs
from google_auth_oauthlib.flow import Flow
class CallbackHandler(BaseHTTPRequestHandler):
code_value = None
def do_GET(self):
qs = parse_qs(urlparse(self.path).query)
CallbackHandler.code_value = (qs.get('code') or [None])[0]
self.send_response(200)
self.end_headers()
self.wfile.write(b'OAuth complete.')
def log_message(self, format, *args):
return
server = HTTPServer(('127.0.0.1', 0), CallbackHandler)
redirect_uri = f'http://127.0.0.1:{server.server_port}/'
flow = Flow.from_client_secrets_file(
'client_secret.json',
scopes=['https://www.googleapis.com/auth/adwords'],
redirect_uri=redirect_uri
)
auth_url, _ = flow.authorization_url(
access_type='offline',
prompt='consent'
)
print(auth_url)
server.handle_request()
flow.fetch_token(code=CallbackHandler.code_value)
Path('google_ads_token.json').write_text(flow.credentials.to_json())
Zwei Parameter sind entscheidend:
access_type='offline'– liefert einen Refresh-Token, nicht nur einen Access-Tokenprompt='consent'– erzwingt einen neuen Zustimmungsbildschirm, selbst wenn der Nutzer zuvor autorisiert hat; erforderlich, um einen neuen Refresh-Token zu erhalten, wenn sich die Scopes geändert haben
Der Refresh-Token hat keine feste Lebensdauer, funktioniert aber nicht mehr, wenn der Nutzer den Zugriff widerruft, er sechs Monate lang nicht verwendet wird, der Nutzer sein Passwort ändert (bei Tokens mit Gmail-Scopes), das Konto Googles Obergrenze für aktive Refresh-Tokens überschreitet oder ein Workspace-Administrator den Scope einschränkt oder eine Sitzungsdauer erzwingt. Planen Sie eine erneute Autorisierung ein.
Scope-Fallstrick bei bestehenden Clients
Wenn die Autorisierungs-URL include_granted_scopes=true setzt und der Nutzer diesem OAuth-Client zuvor andere Scopes gewährt hat (Gmail, Drive, Calendar), gibt Google die Vereinigungsmenge aus alten und neuen Scopes zurück. Die google-auth-oauthlib-Bibliothek lehnt diese Scope-Abweichung standardmäßig ab. Die Umgebungsvariable vor dem Laden des Flows setzen:
import os
os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = '1'
Alternativ include_granted_scopes=true aus der Autorisierungs-URL weglassen (das obige Skript setzt es nicht), sodass der Token nur den explizit angeforderten Scope abdeckt.
Schritt 3: google-ads.yaml
Die Bibliothek liest die Konfiguration aus einer YAML-Datei:
developer_token: <value>
client_id: <value>
client_secret: <value>
refresh_token: <value>
login_customer_id: 1911599764
use_proto_plus: true
Sicherheitsregeln:
- Dateiberechtigungen:
0600(nur Besitzer lesen/schreiben) - Niemals in die Versionskontrolle einchecken
- Außerhalb jedes Git-Repositories speichern
- Für Team-Setups über einen Secrets-Manager verteilen, nicht als geteilte Datei
login_customer_id ist die numerische MCC-ID ohne Bindestriche. Sie teilt der API mit, über welches Manager-Konto der authentifizierte Nutzer auf das Zielkonto zugreift, und ist erforderlich, sobald der Zugriff über ein Manager-Konto erfolgt. Die Ziel-customer_id wird beim Aufruf übergeben, nicht in der Konfiguration.
use_proto_plus ist ein erforderlicher Konfigurationsschlüssel: true wählt die in dieser Anleitung verwendete Proto-Plus-Nachrichtenschnittstelle, false wählt reine Protobuf-Nachrichten, die Google für Arbeiten mit hohen Leistungsanforderungen empfiehlt.
Schritt 4: Python-Client initialisieren
from google.ads.googleads.client import GoogleAdsClient
client = GoogleAdsClient.load_from_storage(
'/path/to/google-ads.yaml',
version='v22'
)
gs = client.get_service('GoogleAdsService')
Der version-Parameter wählt explizit die API-Version aus. Die google-ads-Bibliothek wird mit mehreren parallel installierten Versionen ausgeliefert; die Beispiele hier verwenden v22. Stand Oktober 2026 enthalten aktuelle Bibliotheksversionen v22 nicht mehr (in 33.0.0 entfernt), und 34.0.0 fügt v26 hinzu. Ersetzen Sie die Version daher durch eine aktuelle. Immer die Version angeben – der Standardwert kann veraltet sein oder neuere Felder nicht unterstützen.
Konnektivität prüfen:
cs = client.get_service('CustomerService')
customers = cs.list_accessible_customers()
ids = [r.split('/')[-1] for r in customers.resource_names]
# Beispielausgabe: ['1305475941', '3977581086', '1911599764']
Schritt 5: Leseoperationen (GAQL)
Google Ads verwendet GAQL (Google Ads Query Language), eine SQL-ähnliche Syntax. Alle Leseoperationen laufen über GoogleAdsService.search_stream(), das Paginierung vermeidet und für die meisten Abfragen gegenüber search() bevorzugt wird.
Kampagnen mit Leistungskennzahlen
SELECT
campaign.id,
campaign.name,
campaign.status,
campaign.advertising_channel_type,
campaign.serving_status,
campaign.bidding_strategy_type,
metrics.impressions,
metrics.clicks,
metrics.cost_micros,
metrics.conversions,
metrics.conversions_value,
metrics.ctr,
metrics.average_cpc
FROM campaign
ORDER BY campaign.id
Kampagnenbudgets
SELECT
campaign_budget.id,
campaign_budget.name,
campaign_budget.amount_micros,
campaign_budget.delivery_method,
campaign_budget.status,
campaign.id,
campaign.name
FROM campaign_budget
Anzeigengruppen
SELECT
ad_group.id,
ad_group.name,
ad_group.status,
ad_group.cpc_bid_micros,
campaign.id,
campaign.name
FROM ad_group
ORDER BY campaign.id, ad_group.id
Keywords (nach Impressionen)
SELECT
ad_group_criterion.keyword.text,
ad_group_criterion.keyword.match_type,
ad_group_criterion.status,
ad_group_criterion.criterion_id,
ad_group.id,
ad_group.name,
campaign.id,
campaign.name,
metrics.impressions,
metrics.clicks,
metrics.cost_micros,
metrics.conversions
FROM keyword_view
WHERE ad_group_criterion.type = 'KEYWORD'
ORDER BY metrics.impressions DESC
LIMIT 100
Anzeigen mit Richtlinienstatus
SELECT
ad_group_ad.ad.id,
ad_group_ad.ad.name,
ad_group_ad.ad.type,
ad_group_ad.status,
ad_group_ad.policy_summary.approval_status,
ad_group.id,
ad_group.name,
campaign.id,
campaign.name
FROM ad_group_ad
Conversion-Aktionen
SELECT
conversion_action.id,
conversion_action.name,
conversion_action.status,
conversion_action.type,
conversion_action.category,
conversion_action.include_in_conversions_metric,
conversion_action.counting_type
FROM conversion_action
Python-Ausführungsmuster
def gaql_query(client, customer_id, query):
gs = client.get_service('GoogleAdsService')
results = []
for batch in gs.search_stream(customer_id=customer_id, query=query):
for row in batch.results:
results.append(row)
return results
Schritt 6: Schreiboperationen mit validate_only
Die folgenden Beispiele verwenden Request-Objekte statt Keyword-Argumenten, da das Request-Objekt validate_only enthält. Jeder Mutationsdienst (CampaignService, AdGroupService, AdGroupCriterionService, CampaignBudgetService) folgt demselben Muster:
from google.protobuf import field_mask_pb2
req = client.get_type('MutateCampaignsRequest')
req.customer_id = '1305475941'
req.validate_only = True
op = client.get_type('CampaignOperation')
op.create.name = 'Campaign Name'
op.create.status = client.enums.CampaignStatusEnum.PAUSED
op.create.advertising_channel_type = client.enums.AdvertisingChannelTypeEnum.SEARCH
op.create.campaign_budget = 'customers/1305475941/campaignBudgets/123456789'
op.create.manual_cpc.enhanced_cpc_enabled = False
req.operations.append(op) # .append(), nicht .add()
client.get_service('CampaignService').mutate_campaigns(request=req)
Wesentliche Punkte dieses Musters (mit use_proto_plus: true):
validate_onlyist ein Feld des Request-Objekts, kein Keyword-Argument der Mutate-Methode- Operationen werden über
req.operations.append(op)angehängt;.add()gehört zur reinen Protobuf-Schnittstelle (use_proto_plus: false) - Ressourcenpfade werden hier als explizite Strings geschrieben (
'customers/1305475941/campaigns/22479990461'); die Dienste bieten auch Hilfsmethoden wiecampaign_service.campaign_path(customer_id, campaign_id), die Google gegenüber manuell zusammengesetzten Namen empfiehlt
Drei Prüfpunkte für Änderungen
Zur Sicherheit im Produktivbetrieb durchlaufen Änderungen drei Prüfpunkte:
Prüfpunkt 1 – validate_only=True: Die API validiert die Request-Struktur, Pflichtfelder und Ressourcenreferenzen. Es wird kein Objekt erstellt. Diesen Prüfpunkt zuerst für jede Mutation ausführen.
Prüfpunkt 2 – Erstellung im pausierten Zustand: validate_only=False setzen und das Objekt mit status=PAUSED erstellen. Das Ergebnis mit einer Leseabfrage prüfen, bevor fortgefahren wird.
Prüfpunkt 3 – Aktivierung für den Live-Betrieb: Ein separater API-Aufruf, der nur das status-Feld auf ENABLED aktualisiert. Dies sollte eine explizite Genehmigung erfordern und nicht in die Erstellung integriert werden.
# Gate 3: eine zuvor erstellte pausierte Kampagne aktivieren
req = client.get_type('MutateCampaignsRequest')
req.customer_id = '1305475941'
req.validate_only = False
op = client.get_type('CampaignOperation')
op.update.resource_name = 'customers/1305475941/campaigns/22479990461'
op.update.status = client.enums.CampaignStatusEnum.ENABLED
op.update_mask.CopyFrom(field_mask_pb2.FieldMask(paths=['status']))
req.operations.append(op)
client.get_service('CampaignService').mutate_campaigns(request=req)
Budget aktualisieren
req = client.get_type('MutateCampaignBudgetsRequest')
req.customer_id = '1305475941'
req.validate_only = True
op = client.get_type('CampaignBudgetOperation')
op.update.resource_name = 'customers/1305475941/campaignBudgets/123456789'
op.update.amount_micros = 1_000_000 # $1.00 pro Tag
op.update_mask.CopyFrom(field_mask_pb2.FieldMask(paths=['amount_micros']))
req.operations.append(op)
client.get_service('CampaignBudgetService').mutate_campaign_budgets(request=req)
Anzeigengruppengebot aktualisieren
req = client.get_type('MutateAdGroupsRequest')
req.customer_id = '1305475941'
req.validate_only = True
op = client.get_type('AdGroupOperation')
op.update.resource_name = 'customers/1305475941/adGroups/165827073530'
op.update.cpc_bid_micros = 250_000 # $0.25
op.update_mask.CopyFrom(field_mask_pb2.FieldMask(paths=['cpc_bid_micros']))
req.operations.append(op)
client.get_service('AdGroupService').mutate_ad_groups(request=req)
Keyword-Erstellung
req = client.get_type('MutateAdGroupCriteriaRequest')
req.customer_id = '1305475941'
req.validate_only = True
op = client.get_type('AdGroupCriterionOperation')
op.create.ad_group = 'customers/1305475941/adGroups/165827073530'
op.create.status = client.enums.AdGroupCriterionStatusEnum.PAUSED
op.create.keyword.text = 'example keyword'
op.create.keyword.match_type = client.enums.KeywordMatchTypeEnum.EXACT
req.operations.append(op)
client.get_service('AdGroupCriterionService').mutate_ad_group_criteria(request=req)
Fehlerbehandlung
from google.ads.googleads.errors import GoogleAdsException
try:
response = service.mutate_campaigns(request=req)
except GoogleAdsException as ex:
for error in ex.failure.errors:
print(f'{error.error_code}: {error.message}')
Häufige Fehlercodes und ihre Bedeutung:
| Fehlercode | Ursache |
|---|---|
RESOURCE_NOT_FOUND | Die referenzierte Ressource existiert nicht, wurde entfernt oder hat einen fehlerhaft aufgebauten Ressourcennamen |
DEVELOPER_TOKEN_NOT_APPROVED | Token mit Test Access auf einem Produktionskonto (CLOUD_PROJECT_NOT_APPROVED_FOR_PRODUCTION seit der Abschaffung im September 2026) |
REQUIRED | Fehlendes Pflichtfeld (z. B. Gebotsstrategie bei Kampagnenerstellung) |
UNRECOGNIZED_FIELD | Feld aus einer anderen API-Version oder falscher Feldname |
INVALID_ARGUMENT | Feldwert besteht die Validierung nicht (z. B. negatives Budget) |
PERMISSION_DENIED | OAuth-Nutzer hat keinen Zugriff auf das Zielkonto |
API-Zugriffsstufen
Der Zugriff auf die Google Ads API ist gestuft, nicht binär:
| Stufe | Bereitstellung | Lesen (Produktion) | Schreiben (Produktion) | Schreiben (Testkonten) | Tägliches Operationslimit |
|---|---|---|---|---|---|
| Test Access | Sofort (bis September 2026 aus dem MCC API Center; jetzt automatisch beim Aktivieren der API im Cloud-Projekt) | ❌ | ❌ | ✅ | 15.000 |
| Explorer Access (Stand Oktober 2026 aufgeführt) | Antrag auf der Übersichtsseite der Cloud Console | ✅ | ✅ (einige Dienste eingeschränkt) | ✅ | 2.880 Produktion / 15.000 Test |
| Basic Access | Antrag + Compliance-Prüfung | ✅ | ✅ | ✅ | 15.000 |
| Standard Access | Antrag nach Basic Access + manuelles Audit | ✅ | ✅ | ✅ | Unbegrenzt |
Test Access ist für die Entwicklung mit Google-Ads-Testkonten ausreichend: Authentifizierung, GAQL-Abfragen, validate_only-Tests und vollständiges Lesen/Schreiben. Der Wechsel zu Basic Access hängt von der Compliance-Prüfung ab, nicht von den Ausgaben.
Standard Access entfernt die tägliche Obergrenze für Operationen (funktionsspezifische Aufruflimits gelten weiterhin). Dafür sind ein separater Antrag, der erst nach Basic Access verfügbar ist, und ein manuelles Audit erforderlich; Googles Dokumentation zu Zugriffsstufen nennt keine Ausgabenschwelle.
Testkonten
Testkonten sind kostenlose Google-Ads-Konten ohne Abrechnung, die niemals Anzeigen ausliefern. Test- und Produktionskonten können nicht miteinander interagieren, daher kann ein Testkonto nicht unter Ihrem Produktions-MCC liegen: Erstellen Sie ein separates Test-Manager-Konto, während Sie mit einem Google-Konto angemeldet sind, das nicht mit Ihrem Produktions-MCC verknüpft ist. Erstellen Sie darunter Testkundenkonten und verwenden Sie eines davon während der Test-Access-Entwicklung als Ziel-customer_id (mit dem Test-Manager als login_customer_id).
validate_only über Zugriffsstufen hinweg
validate_only=True funktioniert auf allen Zugriffsstufen, aber Test Access lehnt validate_only-Mutationen auf Produktionskonten weiterhin mit demselben Autorisierungsfehler wie jede andere Anfrage ab. Dies ist keine Einschränkung von validate_only – es ist dieselbe Zugriffskontrolle, die auf alle Schreiboperationen angewendet wird, unabhängig vom validate_only-Flag.
Conversion-Tracking: API-Abfrage und tatsächliche Funktion
Die Google-Ads-Benutzeroberfläche zeigt möglicherweise „Conversion-Tracking einrichten“ als Empfehlung an, selbst wenn eine Conversion-Aktion existiert und aktiviert ist. Die API kann die Existenz einer Conversion-Aktion bestätigen (Typ WEBPAGE, Kategorie PURCHASE, Status ENABLED, include_in_conversions_metric: true), aber dies beweist nur, dass das Aktionsobjekt existiert. Es beweist nicht, dass die Website das entsprechende AW-.../label-Ereignis auslöst, dass das Google-Tag geladen ist oder dass ein Conversion-Signal empfangen wurde.
Bei der Prüfung des Conversion-Trackings die API-Prüfung (Metadaten der Conversion-Aktion) von der Browser-Prüfung (Netzwerk-Tab, Laden des Tags, Ereignisauslösung) trennen. Die API ist die maßgebliche Datenquelle für die Konfiguration; der Browser ist die maßgebliche Datenquelle für die Ausführung.
Das Muster für Backend-Umsatzzuordnung gilt auch hier: Wenn clientseitige Conversion-Ereignisse unzuverlässig sind, serverseitige oder Offline-Conversion-Uploads über den ConversionUploadService der Google Ads API als Fallback einplanen.
API-Versionierung
Die google-ads-Python-Bibliothek wird mit mehreren API-Versionen ausgeliefert. Stand Oktober 2026 fügt die neueste Version (34.0.0) v26 hinzu, und v22 sowie ältere Versionen wurden aus der Bibliothek entfernt. Jede Version fügt GAQL-Felder und Dienstmethoden hinzu, kennzeichnet sie als veraltet oder entfernt sie.
Regeln für die Versionsauswahl:
- Die Version explizit in
load_from_storage(version='v22')angeben. Der Standardwert kann veraltet sein. - Die Versionshinweise zur Google Ads API auf Abkündigungen von Feldern prüfen, bevor ein Upgrade durchgeführt wird.
- Die
search_stream-Methode ist in allen aktuellen Versionen verfügbar und der empfohlene Lesepfad. use_proto_plusmuss explizit gesetzt werden (trueoderfalse); es wählt die Python-Nachrichtenschnittstelle, keine API-Version.- Das Request-Objekt-Muster für Mutationen (
mutate_campaigns(request=req)) enthält Felder auf Anfrageebene wievalidate_only; Googles aktuelle Beispiele übergebencustomer_idundoperationsfür einfache Mutationen weiterhin als Keyword-Argumente.
Lokale Sicherheit
Alle Dateien mit Zugangsdaten müssen außerhalb der Versionskontrolle bleiben:
~/.hermes/
google-ads.yaml # 0600 — Dev Token, OAuth-Client, Refresh Token
google_ads_token.json # 0600 — OAuth-Tokens, Adwords-Scope
google_client_secret.json # 0600 — OAuth-Client-ID + Secret
Für das Arbeits-Repository eine .gitignore hinzufügen:
google-ads.yaml
*_token*.json
*_secret*.json
Eine Vorlagendatei mit Platzhalterwerten kann eingecheckt werden, um die erwartete Struktur zu dokumentieren:
# google-ads.yaml.template — diese Datei einchecken, lokal ausfüllen
developer_token: INSERT_DEV_TOKEN
client_id: INSERT_CLIENT_ID
client_secret: INSERT_CLIENT_SECRET
refresh_token: INSERT_REFRESH_TOKEN
login_customer_id: INSERT_MCC_ID
use_proto_plus: true
Pflichtfelder für häufige Operationen
| Operation | Pflichtfelder |
|---|---|
| Kampagne erstellen (Search) | name, status, advertising_channel_type, campaign_budget, manual_cpc oder Gebotsstrategie, contains_eu_political_advertising |
| Anzeigengruppe erstellen (Search) | name, status, type_, cpc_bid_micros, campaign |
| Keyword erstellen | ad_group, status, keyword.text, keyword.match_type |
| Kampagnenstatus aktualisieren | resource_name, status, update_mask (paths: ['status']) |
| Budget aktualisieren | resource_name, amount_micros, update_mask (paths: ['amount_micros']) |
Ein fehlendes Pflichtfeld gibt REQUIRED mit dem Feldnamen zurück. Eine fehlende update_mask bei einer Update-Operation wird mit FieldMaskError.FIELD_MASK_MISSING abgelehnt.
Gekürztes Testskript
Ein gekürztes Skript (GAQL-Feldlisten und Filter sind mit ... abgekürzt und IDs sind Platzhalter, die vor der Ausführung ergänzt werden müssen), das alle Entitätstypen liest und validate_only-Schreibtests ausführt:
# google_ads_api_test.py — alle Entitäten lesen + validate_only-Schreibtests
import warnings
warnings.filterwarnings('ignore')
from google.ads.googleads.client import GoogleAdsClient
from google.ads.googleads.errors import GoogleAdsException
from google.protobuf import field_mask_pb2
CFG = '/path/to/google-ads.yaml'
CID = '1305475941'
c = GoogleAdsClient.load_from_storage(CFG, version='v22')
gs = c.get_service('GoogleAdsService')
def gaql(query, label):
print(f'\n=== {label} ===')
n = 0
for batch in gs.search_stream(customer_id=CID, query=query):
for row in batch.results:
n += 1
print(f'{n} rows')
# Alle Entitäten lesen
gaql("SELECT customer.id, customer.descriptive_name FROM customer WHERE customer.id = ...", "CUSTOMER")
gaql("SELECT campaign.id, campaign.name, campaign.status, ... FROM campaign", "CAMPAIGNS")
gaql("SELECT campaign_budget.id, campaign_budget.name, ... FROM campaign_budget", "BUDGETS")
gaql("SELECT ad_group.id, ad_group.name, ... FROM ad_group", "AD GROUPS")
gaql("SELECT ad_group_criterion.keyword.text, ... FROM keyword_view WHERE ...", "KEYWORDS")
gaql("SELECT ad_group_ad.ad.id, ... FROM ad_group_ad", "ADS")
gaql("SELECT conversion_action.id, ... FROM conversion_action", "CONVERSIONS")
# Schreibtests
def test_write(name, fn):
print(f'\n--- {name} ---')
try:
fn()
print('PASS')
except GoogleAdsException as e:
for err in e.failure.errors:
print(f'{err.error_code}: {err.message}')
def test_create_campaign():
req = c.get_type('MutateCampaignsRequest')
req.customer_id = CID
req.validate_only = True
op = c.get_type('CampaignOperation')
op.create.name = 'TEST_CAMPAIGN'
op.create.status = c.enums.CampaignStatusEnum.PAUSED
op.create.advertising_channel_type = c.enums.AdvertisingChannelTypeEnum.SEARCH
op.create.campaign_budget = f'customers/{CID}/campaignBudgets/123456789'
op.create.manual_cpc.enhanced_cpc_enabled = False
req.operations.append(op)
c.get_service('CampaignService').mutate_campaigns(request=req)
test_write('Create Campaign (validate_only)', test_create_campaign)
print('\nDone.')
Referenzen
- Dokumentation der Google Ads API
- google-ads-Python-Bibliothek
- GAQL-Referenz
- OAuth 2.0 für Desktop-Apps
- Einen projektspezifischen KI-Assistenten über Telegram entwickeln – gleiches OAuth-Muster, angewendet auf einen anderen Google-Scope
- Referenzarchitektur für eine threadbasierte KI-Betriebsebene – das Betriebsmodell, in das sich die API-Automatisierung einfügt
- Mit kleinem Team skalieren: Dutzende Projekte betreiben – warum API-Automatisierung manuelle UI-Arbeit in großem Maßstab ersetzt