// VorbereitungVoraussetzungen prüfen
- Python 3.9+ installiert
- pip (kommt mit Python)
- Terminal / iTerm2 (Mac) oder WSL (Windows)
- Cursor oder VS Code
- Google-Account mit GSC-Zugriff auf Client-Properties
- GA4-Properties der Clients
- Google Ads MCC oder einzelne Accounts
- DataForSEO Account (kostenloser Test reicht zunächst)
Python prüfen:
python3 --version # sollte 3.9+ zeigen
pip3 --version
// Google Cloud ConsoleService Account einrichten
Ein Service Account deckt GSC + GA4 für alle Clients ab. Einmal erstellt, nur noch per E-Mail zu jeder Property hinzufügen.
1.1 · Google Cloud Projekt erstellen
- → console.cloud.google.com öffnen
- Oben links: „Projekt auswählen" → „Neues Projekt"
- Name: z.B.
seybold-agency-apis - Projekt erstellen und warten bis aktiv
1.2 · APIs aktivieren
- Suche: „Search Console API" → Aktivieren
- Suche: „Google Analytics Data API" → Aktivieren
1.3 · Service Account erstellen
- „+ Dienstkonto erstellen" klicken
- Name:
seybold-reporting(o.ä.) - Beschreibung: „Agency Reporting GSC + GA4"
- Rollen: nicht nötig → „Fertig"
- In der Liste auf den neuen Account klicken → Tab „Schlüssel"
- „Schlüssel hinzufügen" → JSON → herunterladen
~/.credentials/seybold-service-account.json. Auf diese Datei zeigen alle Fetcher.Die Service-Account-E-Mail sieht so aus:
[email protected]
Diese E-Mail-Adresse wird bei jedem Client als Nutzer eingetragen (nächster Schritt).
// ProjektstrukturVerzeichnis anlegen
mkdir -p ~/seybold-intel/{fetchers,data/{gsc,ga4,ads,ai-visibility},reports,clients}
cd ~/seybold-intel
Finale Struktur:
Python-Abhängigkeiten installieren
pip3 install google-api-python-client google-auth \
google-analytics-data google-ads \
requests python-dotenv
.env Datei anlegen
# ~/seybold-intel/.env
SERVICE_ACCOUNT_KEY=/Users/dein-name/.credentials/seybold-service-account.json
DATAFORSEO_LOGIN=[email protected]
DATAFORSEO_PASSWORD=dein-passwort
# .gitignore anlegen (falls Git genutzt wird)
echo ".env\ndata/\n*.json\n!clients/*.json" > .gitignore
// GSC + GA4Service Account zu Client-Properties hinzufügen
3.1 · Search Console
- search.google.com/search-console → Property öffnen
- Einstellungen → Nutzer und Berechtigungen
- „Nutzer hinzufügen" → Service-Account-E-Mail eintragen
- Berechtigung: Eingeschränkt (reicht aus)
3.2 · Google Analytics 4
- analytics.google.com → Admin → Property-Zugriffsverwaltung
- „+" → Nutzer hinzufügen → Service-Account-E-Mail
- Rolle: Leser
3.3 · GSC Fetcher
# fetchers/fetch_gsc.py
import os, json
from dotenv import load_dotenv
from google.oauth2 import service_account
from googleapiclient.discovery import build
from datetime import date, timedelta
load_dotenv()
SCOPES = ['https://www.googleapis.com/auth/webmasters.readonly']
def get_service():
creds = service_account.Credentials.from_service_account_file(
os.getenv('SERVICE_ACCOUNT_KEY'), scopes=SCOPES
)
return build('searchconsole', 'v1', credentials=creds)
def fetch_queries(site_url, days=90):
service = get_service()
end = date.today()
start = end - timedelta(days=days)
response = service.searchanalytics().query(
siteUrl=site_url,
body={
'startDate': str(start),
'endDate': str(end),
'dimensions': ['query', 'page'],
'rowLimit': 5000
}
).execute()
return response.get('rows', [])
def save(data, client_name):
path = f"data/gsc/{client_name}_queries.json"
with open(path, 'w') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
print(f"✓ GSC: {len(data)} Zeilen → {path}")
3.4 · GA4 Fetcher
# fetchers/fetch_ga4.py
import os, json
from dotenv import load_dotenv
from google.oauth2 import service_account
from google.analytics.data_v1beta import BetaAnalyticsDataClient
from google.analytics.data_v1beta.types import (
RunReportRequest, DateRange, Metric, Dimension
)
from datetime import date, timedelta
load_dotenv()
def get_client():
creds = service_account.Credentials.from_service_account_file(
os.getenv('SERVICE_ACCOUNT_KEY'),
scopes=['https://www.googleapis.com/auth/analytics.readonly']
)
return BetaAnalyticsDataClient(credentials=creds)
def fetch_traffic(property_id, days=90):
client = get_client()
end = date.today()
start = end - timedelta(days=days)
req = RunReportRequest(
property=f"properties/{property_id}",
date_ranges=[DateRange(start_date=str(start), end_date=str(end))],
dimensions=[
Dimension(name="sessionDefaultChannelGroup"),
Dimension(name="landingPagePlusQueryString")
],
metrics=[
Metric(name="sessions"),
Metric(name="totalUsers"),
Metric(name="bounceRate"),
Metric(name="averageSessionDuration")
]
)
response = client.run_report(req)
rows = []
for row in response.rows:
rows.append({
"channel": row.dimension_values[0].value,
"page": row.dimension_values[1].value,
"sessions": row.metric_values[0].value,
"users": row.metric_values[1].value,
"bounce_rate": row.metric_values[2].value,
"avg_duration": row.metric_values[3].value
})
return rows
def save(data, client_name):
path = f"data/ga4/{client_name}_traffic.json"
with open(path, 'w') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
print(f"✓ GA4: {len(data)} Zeilen → {path}")
// Google AdsOAuth + Developer Token
4.1 · Developer Token beantragen
- Ads-Konto öffnen → Tools & Einstellungen → API Center
- Developer Token beantragen
- Anwendungsbeschreibung: „Automated reporting for digital marketing agency clients. Internal use only."
- Genehmigung: meist 24–48 Stunden per E-Mail
4.2 · OAuth Client erstellen
- „Anmeldedaten erstellen" → OAuth-Client-ID
- Anwendungstyp: Desktop-App
- Client-ID und Client-Secret notieren
- JSON herunterladen als
oauth-client.json
4.3 · Refresh Token generieren (einmalig)
# pip3 install google-auth-oauthlib
from google_auth_oauthlib.flow import InstalledAppFlow
flow = InstalledAppFlow.from_client_secrets_file(
'oauth-client.json',
scopes=['https://www.googleapis.com/auth/adwords']
)
creds = flow.run_local_server(port=0)
print("Refresh Token:", creds.refresh_token)
Den Refresh Token in die google-ads.yaml eintragen:
# google-ads.yaml (NICHT in Git!)
developer_token: DEIN_DEVELOPER_TOKEN
client_id: DEIN_CLIENT_ID.apps.googleusercontent.com
client_secret: DEIN_CLIENT_SECRET
refresh_token: DEIN_REFRESH_TOKEN
login_customer_id: DEIN_MCC_ID # ohne Bindestriche
4.4 · Ads Fetcher
# fetchers/fetch_ads.py
import json
from google.ads.googleads.client import GoogleAdsClient
def fetch_search_terms(customer_id, days=30):
client = GoogleAdsClient.load_from_storage("google-ads.yaml")
ga_service = client.get_service("GoogleAdsService")
query = f"""
SELECT
search_term_view.search_term,
campaign.name,
ad_group.name,
segments.keyword.info.match_type,
metrics.impressions,
metrics.clicks,
metrics.cost_micros,
metrics.conversions,
metrics.ctr
FROM search_term_view
WHERE segments.date DURING LAST_{days}_DAYS
AND metrics.impressions > 0
ORDER BY metrics.clicks DESC
LIMIT 5000
"""
rows = []
response = ga_service.search(customer_id=customer_id.replace('-',''), query=query)
for row in response:
rows.append({
"search_term": row.search_term_view.search_term,
"campaign": row.campaign.name,
"ad_group": row.ad_group.name,
"match_type": row.segments.keyword.info.match_type.name,
"impressions": row.metrics.impressions,
"clicks": row.metrics.clicks,
"cost_eur": row.metrics.cost_micros / 1_000_000,
"conversions": row.metrics.conversions,
"ctr": row.metrics.ctr
})
return rows
def save(data, client_name):
path = f"data/ads/{client_name}_search_terms.json"
with open(path, 'w') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
print(f"✓ Ads: {len(data)} Zeilen → {path}")
data/ads/ ablegen. Claude Code kann CSV-Dateien genauso auswerten.// DataForSEO + BingAI Visibility Tracking
5.1 · DataForSEO Account
- app.dataforseo.com → Registrieren (kostenloser Test)
- Mindestguthaben: $50 (Pay-as-you-go, ca. $0.01/Query)
- Login + Passwort in
.enveintragen
5.2 · AI Visibility Fetcher
# fetchers/fetch_ai.py
import os, json, requests
from dotenv import load_dotenv
load_dotenv()
BASE_URL = "https://api.dataforseo.com/v3"
AUTH = (
os.getenv('DATAFORSEO_LOGIN'),
os.getenv('DATAFORSEO_PASSWORD')
)
def fetch_ai_overviews(keywords, location_code=2276):
# location_code 2276 = Deutschland
payload = [
{"keyword": kw, "location_code": location_code, "language_code": "de"}
for kw in keywords
]
response = requests.post(
f"{BASE_URL}/serp/google/ai_overview/live/advanced",
auth=AUTH, json=payload
)
return response.json()
def fetch_llm_mentions(brand, location_code=2276):
# Prüft Brand-Erwähnungen in LLM-Antworten
payload = [{"brand": brand, "location_code": location_code}]
response = requests.post(
f"{BASE_URL}/content_analysis/summary/live",
auth=AUTH, json=payload
)
return response.json()
def save(data, client_name, source="ai_overviews"):
path = f"data/ai-visibility/{client_name}_{source}.json"
with open(path, 'w') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
print(f"✓ AI: → {path}")
5.3 · Bing Webmaster Tools (kostenlos)
- bing.com/webmasters → Property für Client hinzufügen
- „Copilot" Tab: zeigt Seiten, die als Quelle in Copilot-Antworten erscheinen
- CSV-Export → in
data/ai-visibility/ablegen - Kein API nötig – monatlich manuell exportieren
| Tool | Kosten | Plattformen | Empfehlung |
|---|---|---|---|
| DataForSEO | ~$0.01/Query | Google AI Overview | ✓ Start hier |
| Bing Webmaster | Kostenlos | Copilot / Bing AI | ✓ Immer nutzen |
| Peec.ai | auf Anfrage | Multi-LLM DACH | Enterprise |
| SerpApi | ab $75/Monat | Google SERP + AIO | Wenn Budget |
// Client Config + RunAlles zusammenführen
6.1 · Client-Config-Datei
// clients/coca-cola.json
{
"name": "Coca-Cola",
"slug": "coca-cola",
"domain": "coca-cola.com",
"gsc_property": "https://www.coca-cola.com/",
"ga4_property_id": "XXXXXXXXX",
"google_ads_customer_id": "XXXX-XXXX-XXXX",
"industry": "Getränke / FMCG",
"brand_terms": ["Coca-Cola", "Coke", "Cola"],
"ai_keywords": [
"cola kaufen online",
"erfrischungsgetränke marken vergleich",
"coca cola zero zucker inhaltsstoffe"
],
"competitors": [
"pepsi.com", "redbull.com", "monster.com"
]
}
6.2 · Haupt-Runner
# run_fetch.py
import json, argparse, sys
from fetchers import fetch_gsc, fetch_ga4, fetch_ads, fetch_ai
from pathlib import Path
def load_client(slug):
path = Path(f"clients/{slug}.json")
if not path.exists():
print(f"❌ Client '{slug}' nicht gefunden in clients/")
sys.exit(1)
return json.loads(path.read_text())
def run(client_slug, sources):
cfg = load_client(client_slug)
slug = cfg["slug"]
print(f"\n→ Fetching: {cfg['name']} | Sources: {', '.join(sources)}\n")
if "gsc" in sources:
data = fetch_gsc.fetch_queries(cfg["gsc_property"])
fetch_gsc.save(data, slug)
if "ga4" in sources:
data = fetch_ga4.fetch_traffic(cfg["ga4_property_id"])
fetch_ga4.save(data, slug)
if "ads" in sources:
data = fetch_ads.fetch_search_terms(cfg["google_ads_customer_id"])
fetch_ads.save(data, slug)
if "ai" in sources:
data = fetch_ai.fetch_ai_overviews(cfg["ai_keywords"])
fetch_ai.save(data, slug, "ai_overviews")
print(f"\n✅ Fertig. Daten in data/ → Claude Code kann jetzt loslegen.\n")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--client", required=True)
parser.add_argument("--sources", default="gsc,ga4,ads,ai")
args = parser.parse_args()
run(args.client, args.sources.split(","))
6.3 · Ausführen
# Alle Quellen für Coca-Cola
python3 run_fetch.py --client coca-cola
# Nur GSC + GA4 (kein Ads)
python3 run_fetch.py --client coca-cola --sources gsc,ga4
# Anderer Client
python3 run_fetch.py --client example-client
// Claude Code PromptsCross-Source-Analysen
Cursor im Projektverzeichnis öffnen. Claude Code hat jetzt Zugriff auf alle JSON-Dateien. Diese Prompts direkt eingeben:
„Vergleiche die GSC-Queries aus data/gsc/coca-cola_queries.json mit den Google Ads Search Terms aus data/ads/coca-cola_search_terms.json. Finde: (1) Keywords wo wir Ads schalten, aber bereits stark organisch ranken – Einsparpotenzial. (2) Keywords mit Ads-Spend aber null organische Sichtbarkeit – Content-Gaps. (3) Organisch starke Queries ohne Ads-Unterstützung – Amplifikationschancen."
„Welche Seiten haben laut GSC viele Impressionen aber unterdurchschnittlichen CTR (unter 2%)? Vergleiche mit den GA4-Bounce-Rates für dieselben URLs. Sortiere nach Optimierungspotenzial."
„Analysiere data/ai-visibility/coca-cola_ai_overviews.json. Welche unserer URLs werden in AI Overviews zitiert? Welche Competitor-Domains erscheinen häufiger? Was sind die häufigsten Themen in AI-Antworten wo wir NICHT zitiert werden?"
„Gruppiere die GSC-Queries nach Themen-Clustern. Zeige pro Cluster: Gesamtimpressionen, durchschnittliche Position, Klicks. Welche Cluster haben hohe Impressionen aber Position > 10? Das sind die Content-Investitionsprioritäten."
// ZusammenfassungZeitaufwand realistisch
| Phase | Einmalig | Pro neuer Client | Monatlich |
|---|---|---|---|
| Google Cloud Setup | ~30 Min | – | – |
| Google Ads OAuth | ~30 Min + 48h Wartezeit | – | – |
| Python + Scripts | ~20 Min | – | – |
| Client Config + Properties | – | ~10 Min | – |
| Daten holen | – | – | ~5 Min |
| Analyse mit Claude Code | – | – | ~15–30 Min |