Implementar Analytics com Claude Code: GA4, GSC, Cloudflare e Receita
Implemente analytics com Claude Code: GA4, GSC, Cloudflare, PV, CTA, receita e testes.
Analytics não é só instalar tag
Implementar analytics é transformar PV, cliques, leitura completa, contatos, cliques em produto e compras em dados que mudam decisões. PV significa page view, a visualização de uma página. Evento é uma ação registrada. Conversão ou key event no GA4 é um resultado de negócio. UTM é a marca de campanha na URL. Consentimento define se o navegador pode enviar dados.
Claude Code ajuda porque transforma plano de medição em código, testes e documentação. O erro que Masa encontrou no site foi acompanhar PV crescendo sem separar clique em produto, formulário concluído e cadastro em recurso gratuito. O tráfego parecia bom, mas a rota de receita não aparecia.
A pilha prática aqui é GA4 para campanhas e eventos-chave, Search Console para query e página, Cloudflare para sinais de borda, Plausible para metas leves e PostHog para funis. Leia também SEO optimization, A/B testing, performance e content funnel audit.
Plano de medição
Peça ao Claude Code uma tabela baseada em decisões.
Crie um plano de analytics para este site de conteúdo.
O objetivo não é só crescer PV, mas melhorar leitura completa, CTA, consultas, cliques em produto e compras.
Use business_question, event_name, trigger, required_params, provider, decision.
Use eventos recomendados de GA4 quando fizer sentido. Eventos próprios em snake_case.
| business_question | event_name | trigger | required_params | provider | decision |
|---|---|---|---|---|---|
| O artigo é lido até o fim? | article_read_complete | Rodapé 70% visível | slug, category, reading_time_sec | GA4/PostHog | Ajustar introdução, títulos e links |
| CTAs recebem clique? | cta_click | CTA de produto, treinamento ou PDF | slug, cta_id, cta_type, target_url | GA4/Plausible/PostHog | Mudar posição e texto |
| O contato foi concluído? | generate_lead | Formulário enviado com sucesso | form_id, lead_source, value, currency | GA4/PostHog | Melhorar formulário e oferta |
| Produto cria intenção? | purchase_link_click | Clique em produto ou Gumroad | product_id, price, currency, slug | GA4/PostHog | Combinar artigo e produto |
| Quais queries valem esforço? | gsc_query_page | Search Console API retorna page/query | page, query, clicks, impressions, ctr, position | GSC | Priorizar título e atualização |
| Tags de navegador perdem tráfego? | edge_page_view | Cloudflare Worker recebe request | path, country, status, duration_ms | Cloudflare | Ver bloqueios e velocidade |
Confira eventos do GA4 em recommended events. Use generate_lead quando encaixar e deixe eventos próprios para ações do artigo.
flowchart LR
Reader["Leitor"]
Consent["Consentimento"]
Browser["browser analytics.js"]
Server["GA4 Measurement Protocol"]
GSC["Search Console API"]
Edge["Cloudflare Worker"]
Dashboard["Conteúdo, receita, qualidade"]
Reader --> Consent --> Browser
Browser --> Server
GSC --> Dashboard
Edge --> Dashboard
Browser --> Dashboard
Server --> Dashboard
Contrato de eventos em JS
O contrato mantém nomes e parâmetros estáveis.
// 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/" }));
}
Separe products e training. Produto indica interesse em guia ou template; treinamento indica demanda de adoção em equipe.
Camada do navegador
Aqui ficam consentimento, UTM, limpeza de parâmetros e envio para GA4, Plausible e PostHog.
// 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);
}
Envie generate_lead só depois do sucesso do formulário. Leitura completa deve disparar uma vez quando o final do artigo aparece.
GA4, GSC e Cloudflare
Eventos confirmados no servidor usam GA4 Measurement Protocol e validation server.
// 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 vem pela 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));
}
Para borda, use Workers Analytics Engine e o exemplo writeDataPoint.
// 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 });
},
};
Não grave e-mail, nome, texto livre nem IP bruto no Cloudflare.
Casos de uso e armadilhas
Caso 1: SEO. Muitas impressões no GSC e CTR baixo pedem título e description melhores. PV alto e leitura baixa pedem intro e estrutura melhores. Caso 2: produtos. purchase_link_click com product_id, price, currency e slug mostra quais artigos levam a ofertas. Caso 3: consultoria. cta_click mede intenção; generate_lead mede formulário concluído. Caso 4: campanhas. UTM precisa sobreviver até o formulário.
Armadilhas: nomes inconsistentes, envio antes de consentimento, conversões duplicadas entre cliente e servidor, tratar GSC como log completo, excesso de scripts prejudicando Core Web Vitals. Divida dashboards em crescimento editorial, funil de receita e qualidade técnica. Verifique GA4 DebugView, Realtime, Plausible Goals, PostHog Events e Cloudflare em até 24 horas.
Para organizar uma instalação existente, products ajuda com templates e training ajuda a revisar plano, código e dashboards em equipe.
PDF grátis: cheatsheet do Claude Code
Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.
Cuidamos dos seus dados e não enviamos spam.
Sobre o autor
Masa
Engenheiro focado em workflows práticos com Claude Code.
Artigos relacionados
Escada de segurança de permissões no Claude Code
Amplie de read-only para edições limitadas, comandos de prova e deploy checks sem perder controle.
Claude Code Small PR Proof Pack: pequenas mudanças fáceis de revisar
Um pacote de prova para PRs do Claude Code: diff, checks, URL pública, CTA e rollback.
Gate de revisão antes do commit com Claude Code
Revisão antes do commit com Claude Code: diff, build, URL pública, Gumroad, consultoria, testes e arquivos fora do escopo.