Analytics mit Claude Code: GA4, GSC, Cloudflare, PV und Umsatz
Claude-Code-Analytics mit GA4, GSC, Cloudflare, PV, CTA, Umsatz-Events und Tests umsetzen.
Analytics beginnt vor dem Tag
Analytics-Implementierung bedeutet, PV, Klicks, gelesene Artikel, Anfragen, Produktklicks und Käufe in entscheidbare Daten zu übersetzen. PV heißt Page View. Ein Event ist eine aufgezeichnete Handlung. Eine Conversion oder ein GA4 Key Event ist ein geschäftlich relevantes Ergebnis. UTM-Parameter markieren Kampagnen in der URL. Consent entscheidet, ob Browser-Analytics senden darf.
Claude Code hilft, weil es Messplan, Code, Tests und Dokumentation in einem Arbeitsfluss verbinden kann. Masas Fehler auf dieser Website war, PV-Wachstum zu betrachten, ohne Produktklicks, Formularabschlüsse und kostenlose Ressourcen getrennt zu messen. Der Traffic sah gut aus, aber der Umsatzpfad blieb unsichtbar.
Diese Anleitung nutzt GA4 für Kampagnen und Key Events, Search Console für Suchanfragen und Seiten, Cloudflare für Edge-Signale, Plausible für leichte Ziele und PostHog für Funnels. Ergänzend passen SEO-Optimierung, A/B-Tests, Performance und Content-Funnel-Audit.
Messplan
Lassen Sie Claude Code zuerst eine Entscheidungstabelle erstellen.
Erstelle einen Analytics-Plan für diese Content-Website.
Ziel sind nicht nur PV, sondern gelesene Artikel, CTA-Klicks, Anfragen, Produktklicks und Käufe.
Nutze business_question, event_name, trigger, required_params, provider, decision.
Nutze GA4 Recommended Events, wo sie passen. Eigene Events in snake_case.
| business_question | event_name | trigger | required_params | provider | decision |
|---|---|---|---|---|---|
| Wird der Artikel gelesen? | article_read_complete | Footer zu 70% sichtbar | slug, category, reading_time_sec | GA4/PostHog | Intro, Überschriften, interne Links ändern |
| Werden CTAs geklickt? | cta_click | Produkt-, Training- oder PDF-CTA | slug, cta_id, cta_type, target_url | GA4/Plausible/PostHog | Position und Text ändern |
| Wird eine Anfrage abgeschlossen? | generate_lead | Formular erfolgreich gesendet | form_id, lead_source, value, currency | GA4/PostHog | Formular und Angebot verbessern |
| Erzeugen Produktlinks Kaufinteresse? | purchase_link_click | Produktseite oder Gumroad geklickt | product_id, price, currency, slug | GA4/PostHog | Artikel und Produkt abstimmen |
| Welche Queries sind wertvoll? | gsc_query_page | Search Console API liefert page/query | page, query, clicks, impressions, ctr, position | GSC | Titel und Updates priorisieren |
| Fehlen Browser-Tags? | edge_page_view | Cloudflare Worker erhält Request | path, country, status, duration_ms | Cloudflare | Blocker und Geschwindigkeit finden |
GA4-Events werden gegen recommended events geprüft. generate_lead passt als Standard; Artikelabschluss bleibt ein eigenes Event.
flowchart LR
Reader["Leser"]
Consent["Consent"]
Browser["browser analytics.js"]
Server["GA4 Measurement Protocol"]
GSC["Search Console API"]
Edge["Cloudflare Worker"]
Dashboard["Content, Umsatz, Qualität"]
Reader --> Consent --> Browser
Browser --> Server
GSC --> Dashboard
Edge --> Dashboard
Browser --> Dashboard
Server --> Dashboard
Event-Vertrag in JS
Der Vertrag hält Namen und Pflichtparameter stabil.
// event-plan.mjs
import { pathToFileURL } from "node:url";
export const eventPlan = {
article_read_complete: { required: ["slug", "category", "reading_time_sec"], providers: ["GA4", "PostHog"] },
cta_click: { required: ["slug", "cta_id", "cta_type", "target_url"], providers: ["GA4", "Plausible", "PostHog"] },
generate_lead: { required: ["form_id", "lead_source", "value", "currency"], providers: ["GA4", "PostHog"] },
purchase_link_click: { required: ["product_id", "price", "currency", "slug"], providers: ["GA4", "PostHog"] },
campaign_landing: { required: ["utm_source", "utm_medium", "utm_campaign"], providers: ["GA4"] },
};
export function validateEvent(name, params = {}) {
const contract = eventPlan[name];
if (!contract) return { ok: false, missing: ["known_event_name"] };
const missing = contract.required.filter((key) => params[key] === undefined || params[key] === "");
return { ok: missing.length === 0, missing };
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
console.log(validateEvent("cta_click", { slug: "claude-code-analytics-implementation", cta_id: "products_footer", cta_type: "product", target_url: "/en/products/" }));
}
products und training sind unterschiedliche CTAs. Produktklicks zeigen Template-Interesse; Training-Klicks zeigen Rollout- oder Beratungsbedarf.
Browser-Schicht
Diese Schicht bündelt Consent, UTM, Parameterbereinigung und Provider-Versand.
// browser-analytics.js
const CONSENT_KEY = "analytics_consent";
const UTM_KEYS = ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"];
function inBrowser() {
return typeof window !== "undefined" && typeof localStorage !== "undefined";
}
function hasConsent() {
return inBrowser() && localStorage.getItem(CONSENT_KEY) === "granted";
}
function cleanParams(params = {}) {
return Object.fromEntries(Object.entries(params).filter(([, value]) => value !== undefined && value !== null && value !== "").map(([key, value]) => [key, typeof value === "boolean" ? Number(value) : value]));
}
export function setAnalyticsConsent(state) {
if (!inBrowser()) return;
localStorage.setItem(CONSENT_KEY, state);
window.gtag?.("consent", "update", { analytics_storage: state, ad_storage: "denied" });
}
export function readUtmParams() {
if (!inBrowser()) return {};
const current = new URLSearchParams(window.location.search);
const saved = JSON.parse(localStorage.getItem("landing_utm") || "{}");
const next = { ...saved };
for (const key of UTM_KEYS) {
const value = current.get(key);
if (value) next[key] = value;
}
localStorage.setItem("landing_utm", JSON.stringify(next));
return next;
}
export function trackEvent(name, params = {}) {
if (!hasConsent()) return;
const payload = cleanParams({ ...readUtmParams(), ...params });
window.gtag?.("event", name, payload);
window.plausible?.(name, { props: payload });
window.posthog?.capture(name, payload);
}
generate_lead wird erst nach erfolgreichem Formularversand gesendet. Artikelabschluss wird einmal gesendet, wenn der Footer sichtbar wird.
GA4, GSC und Cloudflare
Serverbestätigte Ergebnisse gehen über GA4 Measurement Protocol und werden mit dem validation server geprüft.
// ga4-server-event.mjs
import { pathToFileURL } from "node:url";
const { GA4_MEASUREMENT_ID, GA4_API_SECRET, GA4_DEBUG } = process.env;
if (!GA4_MEASUREMENT_ID || !GA4_API_SECRET) throw new Error("GA4_MEASUREMENT_ID and GA4_API_SECRET are required");
export async function sendGa4Event({ clientId, name, params = {} }) {
const endpoint = new URL(GA4_DEBUG === "1" ? "https://www.google-analytics.com/debug/mp/collect" : "https://www.google-analytics.com/mp/collect");
endpoint.searchParams.set("measurement_id", GA4_MEASUREMENT_ID);
endpoint.searchParams.set("api_secret", GA4_API_SECRET);
const response = await fetch(endpoint, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ client_id: clientId, events: [{ name, params }] }) });
if (!response.ok) throw new Error("GA4 request failed with status " + response.status);
if (GA4_DEBUG === "1") {
const result = await response.json();
if (result.validationMessages?.length) throw new Error(JSON.stringify(result.validationMessages, null, 2));
}
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
await sendGa4Event({ clientId: "555.1234567890", name: "generate_lead", params: { form_id: "training", lead_source: "article_footer", value: 1, currency: "USD" } });
console.log("sent");
}
Search Console kommt über die Search Analytics API.
// gsc-query.mjs
import { pathToFileURL } from "node:url";
const { GSC_ACCESS_TOKEN, GSC_SITE_URL = "https://example.com/" } = process.env;
if (!GSC_ACCESS_TOKEN) throw new Error("GSC_ACCESS_TOKEN is required");
export async function querySearchConsole({ startDate, endDate, pageContains }) {
const endpoint = "https://www.googleapis.com/webmasters/v3/sites/" + encodeURIComponent(GSC_SITE_URL) + "/searchAnalytics/query";
const response = await fetch(endpoint, {
method: "POST",
headers: { authorization: "Bearer " + GSC_ACCESS_TOKEN, "content-type": "application/json" },
body: JSON.stringify({ startDate, endDate, dimensions: ["page", "query"], dimensionFilterGroups: pageContains ? [{ filters: [{ dimension: "page", operator: "contains", expression: pageContains }] }] : [], rowLimit: 25 }),
});
if (!response.ok) throw new Error("Search Console request failed with status " + response.status);
return response.json();
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
const data = await querySearchConsole({ startDate: "2026-05-01", endDate: "2026-05-31", pageContains: "/blog/claude-code-analytics-implementation" });
console.log(JSON.stringify(data.rows ?? [], null, 2));
}
Für Edge-Signale nutzen Sie Workers Analytics Engine und das writeDataPoint-Beispiel.
// cloudflare-worker.js
function json(data, status = 200) {
return new Response(JSON.stringify(data), { status, headers: { "content-type": "application/json" } });
}
export default {
async fetch(request, env) {
if (request.method !== "POST") return json({ ok: false, error: "method_not_allowed" }, 405);
const event = await request.json().catch(() => null);
if (!event?.event_name || !event?.slug) return json({ ok: false, error: "event_name_and_slug_required" }, 400);
const country = request.cf?.country || request.headers.get("cf-ipcountry") || "XX";
env.ANALYTICS?.writeDataPoint({ blobs: [event.event_name, event.slug, event.cta_id || "", country], doubles: [Number(event.value || 1)], indexes: [String(event.slug).slice(0, 96)] });
return json({ ok: true });
},
};
Keine E-Mail-Adressen, Namen, Freitextfelder oder rohen IPs in Cloudflare speichern.
Use Cases und Fehler
Use Case 1: SEO. Viele GSC-Impressions und niedrige CTR bedeuten Titel- oder Description-Arbeit. Viel PV und niedriger Artikelabschluss bedeuten Intro- oder Strukturproblem. Use Case 2: Produkte. purchase_link_click mit product_id, price, currency und slug zeigt Umsatzinteresse je Artikel. Use Case 3: Training. cta_click zeigt Interesse, generate_lead zeigt abgeschlossenes Formular. Use Case 4: Kampagnen. UTM muss bis zur Anfrage erhalten bleiben.
Fehler: Event-Namen driften, Events werden vor Consent gesendet, Client und Server zählen doppelt, GSC wird als vollständiges Log gelesen, zu viele Drittanbieter verschlechtern Core Web Vitals. Trennen Sie Dashboards in Content-Wachstum, Umsatz-Funnel und technische Qualität. Prüfen Sie GA4 DebugView, Realtime, Plausible Goals, PostHog Events und Cloudflare innerhalb von 24 Stunden.
Für vorhandene Setups helfen products bei Vorlagen und training bei Messplan, Implementierungsreview und Dashboard-Vereinfachung.
Kostenloses PDF: Claude-Code-Cheatsheet
E-Mail eintragen und eine Seite mit Befehlen, Review-Gewohnheiten und sicheren Workflows herunterladen.
Wir schützen Ihre Daten und senden keinen Spam.
Über den Autor
Masa
Engineer für praktische Claude-Code-Workflows und Team-Einführung.
Ähnliche Artikel
Claude Code Permission Safety Ladder: Zugriff kontrolliert erweitern
Von read-only zu begrenzten Änderungen, Prüfbefehlen und Deploy-Checks mit klarer Kontrolle.
Claude Code Small PR Proof Pack: kleine Änderungen reviewbar machen
Ein Proof Pack für Claude-Code-PRs: Diff, Checks, öffentliche URL, CTA-Pfad und Rollback.
Claude-Code-Review-Gate vor dem Commit
Vor dem Commit mit Claude Code prüfen: Diff, Build, öffentliche URL, Gumroad-Links, Beratung-CTA, fehlende Tests und fremde Dateien.