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
Como pedir ao Claude Code para mexer em um único arquivo
Do desastre em que um 'deixa melhor' alterou 40 linhas nasceu um template de prompt que limita o escopo, valida e permite reverter.
Recuperar de negações de permissão no Claude Code sem enfraquecer guardrails
Transforme um comando negado em plano seguro com motivo, alternativa, provas e critérios de nova tentativa.
Claude Code Harness Smoke Test: prova de 15 minutos antes de confiar em um agente
Um smoke test para escopo, áreas bloqueadas, comandos de prova, URL pública e CTAs de receita no Claude Code.