Tips & Tricks (更新: 2026/6/3)

用 Claude Code 实现 Analytics:GA4、GSC、Cloudflare 与收入分析

用 Claude Code 设计 GA4、GSC、Cloudflare 计量,追踪 PV、CTA、收入路径与验证。

用 Claude Code 实现 Analytics:GA4、GSC、Cloudflare 与收入分析

Analytics 实现不只是安装标签

Analytics 实现,是把 PV、点击、读完文章、咨询、商品点击和购买路径变成能指导决策的数据。PV 是页面被浏览的次数;event 是一次行为记录;conversion 或 GA4 key event 是业务上认为有价值的行为;UTM 是写在 URL 里的来源标记;consent 是用户是否允许浏览器端计量的规则。

Claude Code 的价值不只是生成代码,而是把测量计划、事件契约、测试和发布检查放进同一个工作流。Masa 在这个站点踩过的坑,是只看 PV 增长,却没有分开追踪商品链接点击、咨询表单完成和免费资源注册。流量看起来不错,但收入路径不可解释,后来只能重做事件名和看板。

这篇文章使用一个实用组合:GA4 看活动和关键事件,Search Console 看搜索 query 与页面需求,Cloudflare 看边缘请求信号,Plausible 看轻量目标,PostHog 看漏斗和产品行为。相关主题可以继续看 SEO 优化A/B 测试性能优化内容漏斗审计

先写测量计划

先让 Claude Code 从业务问题反推事件,而不是从工具开始堆代码。

请为这个内容站制定 analytics 实现计划。
目标不只是 PV 增长,还包括读完文章、CTA 点击、咨询、商品点击和购买路径优化。
请使用 business_question, event_name, trigger, required_params, provider, decision 列。
能使用 GA4 推荐事件时优先使用;自定义事件用 snake_case。
business_questionevent_nametriggerrequired_paramsproviderdecision
文章是否被读完article_read_complete页脚区域 70% 可见slug, category, reading_time_secGA4/PostHog改导入、标题层级和内部链接
CTA 是否被点击cta_click产品、培训或免费 PDF CTA 被点击slug, cta_id, cta_type, target_urlGA4/Plausible/PostHog调整 CTA 位置和文案
咨询是否完成generate_lead表单提交成功form_id, lead_source, value, currencyGA4/PostHog修表单和咨询说明
商品链接是否创造购买意图purchase_link_click商品页或 Gumroad 链接被点击product_id, price, currency, slugGA4/PostHog调整文章与商品匹配
哪些搜索 query 有价值gsc_query_pageSearch Console API 返回 page/querypage, query, clicks, impressions, ctr, positionGSC决定标题和追记内容
浏览器标签是否漏量edge_page_viewCloudflare Worker 收到请求path, country, status, duration_msCloudflare发现拦截和速度问题

GA4 推荐事件要参考官方 recommended eventsgenerate_lead 和真实购买可以靠近标准事件;文章读完和商品链接点击则适合作为自定义事件。

flowchart LR
  Reader["读者"]
  Consent["同意状态"]
  Browser["browser analytics.js"]
  Server["GA4 Measurement Protocol"]
  GSC["Search Console API"]
  Edge["Cloudflare Worker"]
  Dashboard["内容、收入、质量看板"]

  Reader --> Consent --> Browser
  Browser --> Server
  GSC --> Dashboard
  Edge --> Dashboard
  Browser --> Dashboard
  Server --> Dashboard

用 JS 固定事件契约

事件契约是事件名、必填参数和发送目标的约定。把它放在代码里,Claude Code 增加事件时就能同步更新测试。

// 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: "/zh/products/",
  }));
}

产品页培训咨询 要分开测。前者代表读者想要模板或教材,后者代表团队导入需求。把它们都叫 button_click 会让看板失去判断力。

浏览器端事件层

浏览器端负责同意、UTM 保存、参数清理和多工具发送。不要在组件里到处直接调用 gtag

// 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);
}

读完文章可以用 IntersectionObserver 在页脚可见时发送。表单要在提交成功后才发送 generate_lead,不能在按钮点击时就算作线索。

GA4、GSC 与 Cloudflare 的代码例子

后端确认的购买和咨询完成,可以用 GA4 Measurement Protocol 补齐。实现时要阅读 Measurement Protocolvalidation 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 用来回答搜索需求,不是替代 GA4。通过官方 Search Analytics API 取得 query、page、clicks、impressions、CTR 和 position。

// 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));
}

Cloudflare 可以补浏览器标签缺失的视角。参考 Workers Analytics EnginewriteDataPoint 示例

// 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 });
  },
};

Cloudflare 层不要保存邮箱、姓名、自由输入内容和原始 IP。只保留 slug、事件名、国家级信息、状态和耗时。

用例、坑和发布检查

用例一是 SEO 内容:GSC impression 高但 CTR 低,就改标题和 description;PV 高但读完率低,就改导入、结构和代码例子。用例二是产品导线:用 purchase_link_click 追踪商品点击,带上 product_idpricecurrencyslug。用例三是咨询导线:cta_click 只表示兴趣,generate_lead 才表示表单成功。用例四是广告和 SNS:首次落地时保存 UTM,让最终线索仍能带来源。

常见坑包括事件名漂移、同意前发送、服务端和浏览器重复计算转化、GSC 数据被当成完整日志、第三方脚本拖慢 Core Web Vitals。看板建议分成内容增长、收入漏斗和实现质量三张。发布后 24 小时内检查 GA4 DebugView、Realtime、Plausible Goals、PostHog Events 和 Cloudflare 聚合。

我会给每个事件再加一列“下周要做什么”。例如 article_read_complete 低于 35% 时,先改前三段和第一个代码例子;purchase_link_click 高但购买少时,先改商品页首屏和价格说明;cta_click 高但 generate_lead 低时,先减表单字段,而不是继续改文章标题。这样做的好处是,analytics 不会变成漂亮但没人使用的报表。

Search Console 的数据也要谨慎解释。一个 query 在 1 天内排名变化很大,不代表文章马上要重写;但同一主题连续 2 到 4 周都有 impression、CTR 又低,就值得让 Claude Code 生成标题候选、补充 FAQ、增加内部链接。Cloudflare 的边缘数据则适合回答“浏览器标签有没有漏量”,不适合直接替代 GA4 的同意后行为分析。

发布检查时,我会让 Claude Code 输出一张 receipt:改了哪些事件、哪些代码片段通过 node --check、GA4 debug 是否返回 validation message、GSC token 是否只读、Cloudflare blobs 是否没有个人信息。这个 receipt 比口头说“埋点已完成”更可靠。

如果要把现有计量整理成能改善收入的状态,可以从 产品与模板Claude Code 培训与导入咨询 开始。重点不是增加更多埋点,而是留下能改变内容、产品和收入决策的数据。

#Claude Code #analytics #GA4 #Plausible #PostHog
免费

免费 PDF: Claude Code 速查表

输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。

我们会妥善保护你的信息,不发送垃圾邮件。

把 Claude Code 变成真正能带来结果的工作流

先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。

Masa

关于作者

Masa

专注 Claude Code 实务流程、团队导入和内容转化的工程师。