Google-Ads-Developer-Token-Approval: die 6-Wochen-Wartezeit, und wie du sie überspringst
Server-Side-Conversion-Uploads via Google-Ads-API verlangen einen Developer-Token. Approval dauert 4 bis 6 Wochen Hin-und-Her mit Google. Ein zentraler Broker abstrahiert den Token, ohne deine Conversion-Daten je zu sehen, hier ist, wie die Architektur verdrahtet ist und warum sie keinen Datenschutz-Kompromiss eingeht.
Zwei Credentials, nicht eines
Die Authentifizierung gegen die Google-Ads-API braucht zwei verschiedene Credentials, und das ist die Quelle aller Reibung:
- Einen Developer-Token. Gehört dem, der die Anwendung geschrieben hat, die die API nutzt. Identifiziert die Integration gegenüber Google, gated API-Quota, ist das, was Google in der Approval prüft. Einer pro Integration, unabhängig davon, wieviele Kunden die Integration nutzen.
- Ein OAuth-Credential. Gehört jedem einzelnen Ad-Account-Inhaber. Identifiziert, welcher Kunde uploadet und an welche Customer-ID. Wird sofort über den Standard-OAuth-Handshake ausgegeben, keine Prüfung.
Die OAuth-Seite ist schnell und gut etabliert. Die Developer-Token-Seite ist, wo das 4-bis-6-Wochen-Fenster lebt.
Wie die Developer-Token-Approval wirklich abläuft
Jedes neue Google-Cloud-Projekt, das mit der Google-Ads-API sprechen will, startet im Basic Access: 15.000 API-Operationen pro Tag, nur Sandbox gegen Test-Accounts. Nützlich für Entwicklung, nutzlos für produktive Conversion-Uploads.
Um Standard Access zu bekommen, was du brauchst, um echte Conversions hochzuladen, reichst du eine schriftliche Anwendung bei Google ein. Das Formular fragt nach Use-Case-Beschreibung, erwartetem täglichen Volumen, Integrationsarchitektur, Datenhandling-Praktiken und Screenshots der Integration. Google prüft. Prüfungen bedeuten Hin-und-Her: Klärungsfragen, Anfragen für mehr Screenshots, oft Follow-up-E-Mails zu Edge-Cases.
Die veröffentlichte Ziel-Bearbeitungszeit ist "ein paar Wochen". Der realistische Durchschnitt über die Kunden, die wir beobachtet haben, sind 4 bis 6 Wochen, gelegentlich länger, wenn Googles Review-Queue voll ist. Es gibt keinen Eskalations-Pfad für einzelne kleine Kunden.
Resultat: ein kleiner WordPress-Shop, der Google-Ads-Conversions server-side tracken will, muss über einen Monat warten, bevor er überhaupt anfangen kann.
Warum "einfach Token selbst hosten" ein Non-Starter ist
Zwei Gründe, warum der naheliegende Workaround, einen Developer-Token approven lassen, mit allen Kunden teilen, in der Praxis nicht funktioniert.
Erstens verbietet Googles Developer-Token-Policy ausdrücklich das Teilen von Tokens über Kunden hinweg, die du nicht selbst betreibst. Der Token repräsentiert dich als Integrations-Autor, der für den Daten-Umgang einsteht. Ihn an Dritte zu verleihen, verstößt gegen die Terms of Service.
Zweitens, selbst wenn du die Policy ignorierst, würde der Audit-Trail das sofort sichtbar machen. Google verknüpft API-Operationen in seinen internen Logs mit dem Developer-Token. Wenn 500 unverbundene Kunden-Customer-IDs alle unter einem Developer-Token auftauchen, ist strukturell etwas schief und Google merkt es.
Der legitime Weg, einen Developer-Token über viele Kunden zu nutzen, ist, dass der Developer-Token-Inhaber im Dispatch-Pfad bleibt, also tatsächlich die Integration ist, die den Upload abwickelt, nicht nur ein Credential-Verleiher.
Die Phase-2-Broker-Architektur
Beaconry betreibt einen zentralen Cloudflare Worker, der Beaconrys eigenen genehmigten Developer-Token hält. Die Kunden-WordPress-Installation sieht diesen Token nicht. Die Kunden-WordPress-Installation hält einen OAuth-Refresh-Token, ausgestellt für den Google-Account des Kunden, gescopet auf den Ad-Account des Kunden.
Der Flow bei jedem Conversion-Upload:
- WordPress baut den Upload-Payload (Customer-ID, Conversion-Action-ID, gclid, Wert, Währung).
- WordPress prägt einen frischen Access-Token aus seinem gespeicherten Refresh-Token (Standard-OAuth-Refresh, spricht direkt mit Googles Token-Endpoint, läuft nicht über den Broker).
- WordPress schickt Payload + Access-Token an Beaconrys Broker.
- Broker rate-limitet (max N Uploads/Sek pro Kunde, verhindert versehentliche Loops), hängt Beaconrys Developer-Token im Request-Header an, leitet weiter an
googleads.googleapis.com. - Google validiert den OAuth-Token (muss zur Customer-ID passen), validiert den Developer-Token (Beaconrys), akzeptiert oder lehnt ab.
- Broker streamt die Antwort zurück an WordPress.
Der Broker ist eine Transit-Schicht für den Upload-Body. Er rate-limitet, hängt den Developer-Token-Header an, leitet weiter. Der Body ist HTTPS-verschlüsselt im Transit und wird nicht geloggt oder gespeichert.
Was der Broker NICHT sieht
Architektonisch ist der Broker ein privilegierter Forwarder. Es gibt eine nicht-triviale Vertrauensfrage: woher wissen Kunden, dass wir die Bodies nicht lesen? Drei konkrete Zusagen:
- Keine Body-Persistenz. Der Worker-Code ist aus einem öffentlich einsehbaren Source-Repo deployt. Keine KV-Writes, keine Durable-Object-Writes, keine Log-Zeilen, die den Request-Body enthalten. Cloudflare Workers loggen Request-Metadaten (Pfad, Status, Timing), aber der Body ist nicht in diesen Logs.
- End-to-End-Verschlüsselung von WP zu Google. Der TLS-Handshake schließt zwischen WordPress und
googleads.googleapis.comüber das transparente Forward des Brokers. Der Broker terminiert TLS, um den Developer-Token-Header anzuhängen; er hat keinen Zugriff auf den OAuth-Refresh-Token (der bleibt in WP und berührt den Broker nie). - Kunden-Ad-Account-IDs sichtbar, Conversion-Content nicht. Der Broker loggt, für welche Customer-ID ein Upload ist (nötig für Rate-Limiting und Quota-Allokation). Er loggt keine gclids, Conversion-Werte oder Visitor-Level-Daten.
Der Trade-off ist real und wir tun nicht so, als ob nicht: Kunden tauschen "betreibe deinen eigenen Cloud-Run-Container"-Komplexität gegen "vertraue Beaconrys Broker-Code". Kunden, die diesen Trade nicht machen können, haben einen expliziten Ausgang, sie können den Broker selbst deployen (er ist Open-Source), ihren eigenen Developer-Token mitbringen (4-bis-6-Wochen-Warten taucht wieder auf) und ihn selbst betreiben.
Datenschutz-Garantien: was beim Kunden bleibt
Die Asymmetrie, die das Broker-Pattern funktionieren lässt: Refresh-Tokens verlassen die Kunden-WordPress nie.
- OAuth-Refresh-Token: verschlüsselt im Ruhezustand in WP, wird nur genutzt, um kurzlebige Access-Tokens direkt von Googles Endpoint zu prägen.
- Access-Tokens: in WP geprägt, einmal pro Upload genutzt, laufen in ca. 1 Stunde ab.
- Developer-Token: lebt nur im Broker, wird nie an WP geschickt.
Falls der Broker je kompromittiert wird, bekommt der Angreifer Beaconrys Developer-Token (wir würden ihn revoken und neu beantragen, schmerzhaft aber abgegrenzt), kann aber keinen einzelnen Kunden-Ad-Account impersonieren, weil er keinen Kunden-Refresh-Token hat. Wenn die WP eines Kunden kompromittiert wird, bekommt der Angreifer den Refresh-Token dieses einen Kunden (über Googles Account-Security-Panel revokebar), kann aber nicht in andere Kunden-Ad-Accounts uploaden.
Vergleich zu "Broker hält die Refresh-Tokens aller Kunden"-Patterns: ein einzelner Broker-Compromise würde alle Kunden gleichzeitig verbrennen. Beaconrys Split vermeidet das.
Latenz und Rate-Limits
Ein Worker-Hop fügt grob 5-15 ms gegenüber direkt-WP-zu-Google hinzu. Echte Conversion-Upload-Latenz ist von der Google-Ads-API selbst dominiert (typisch 200-500 ms server-side), der Broker-Hop liegt im Rauschen.
Rate-Limits im Broker sind pro Customer-ID konfiguriert, default 50 Uploads pro Sekunde. Das liegt weit über jedem plausiblen legitimen Volumen einer Small-to-Mid-E-Commerce-Site. Das Cap existiert, um Loops und entlaufene Integrationen früh zu fangen, bevor sie Googles Quota für alle, die sich den Developer-Token teilen, leerräumen.
Failure-Modes
Die ehrlichen Failure-Modes, die aufgetreten sind oder auftreten könnten:
- Kunden-Google-Account revoket den OAuth-Grant. Token läuft ab, Broker leitet ein 401 von Google an WP weiter, Dashboard zeigt "Mit Google neu verbinden". Kunde klickt Connect, OAuth-Handshake wiederholt sich, Konfiguration wiederhergestellt. Conversion-Rule-IDs und Customer-ID bleiben in WP.
- Broker-Outage. Cloudflare Worker fällt aus (selten, aber möglich). WP retried mit Exponential-Backoff für ca. 24 Stunden. Darüber hinaus sind Conversions, die für diesen Zeitraum gequeuet waren, verloren. Status-Page-Integration alarmiert den Operator vor diesem Fenster.
- Google-Rate-Limit greift. Broker reicht das 429 zurück an WP. WP retried mit Backoff. Falls der Kunde tatsächlich über seiner Per-Customer-ID-Quota liegt, sieht er Retries plateau-en und muss mit Google über Quota sprechen.
- Beaconrys Developer-Token wird revoket. Service degradiert für alle gleichzeitig (der Failure-Case, der für Self-Deployment spricht, falls du das nicht tolerieren kannst). Wir haben Prozesse, um Token-Health zu monitoren, aber das ist das Restrisiko, das Kunden tragen.
Fazit
Wenn du Server-Side-Google-Ads-Conversion-Uploads auf einer kleinen WP-Site willst, ist die Wahl: 4-bis-6-Wochen auf deinen eigenen Developer-Token warten, oder ein Broker-Pattern nutzen, das den Token abstrahiert, ohne deine Daten-Hoheit zu kompromittieren. Der Phase-2-Broker ist Letzteres, mit der architektonischen Eigenschaft, dass Kunden-Refresh-Tokens in der Kunden-WP bleiben, nur Beaconrys Developer-Token zentral lebt. Gleiches Resultat am Google-Ads-API-Endpoint, sehr unterschiedliche Time-to-First-Conversion.