关于 product-analytics
面向产品与工程团队的产品分析技能,涵盖事件设计、同意管理、漏斗与队列分析及实验,可用于多个指定分析平台。
主要功能
- 01类型化事件分类与命名
- 02支持同意管理的追踪模式
- 03用户识别与身份合并
- 04漏斗与队列分析
- 05基于功能标志的 A/B 测试
适用场景
- 01规划新产品的事件追踪
- 02重构不一致的分析事件
- 03在追踪前实现用户同意
- 04衡量注册或结账流失
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ travisjneuman/ .claude --skill product-analytics安装后在 Claude Code 中输入/product-analytics确认已加载。
详细介绍
产品分析
概述
本技能涵盖产品分析系统的设计与实现,帮助从用户行为中获取可执行的洞察。内容包括事件分类设计、与主流平台(PostHog、Amplitude、Mixpanel、Segment)的分析 SDK 集成、漏斗与群组分析、A/B 测试与功能标志、用户旅程映射、符合 GDPR 要求的同意管理,以及自定义指标定义。
在为新产品添加分析功能、重新设计事件跟踪系统、搭建 A/B 测试基础设施、实现同意管理,或为产品团队构建自定义仪表板时,请使用此技能。
核心原则
- 先设计分类体系,再编写代码 - 设计良好的事件命名规范和属性架构,可避免分析工作中最常见的失败:数据不一致、无法查询。先就命名规范达成一致。
- 跟踪操作,而不是页面 - 页面浏览能告诉你用户去了哪里;包含上下文的事件能告诉你用户做了什么以及为什么。聚焦于用户操作:
project_created、file_uploaded、subscription_upgraded。 - 先识别用户,再进行跟踪 - 每个事件都需要用户身份。用户注册前的匿名事件,应在用户登录后关联到其已验证身份(别名/合并)。
- 必须征得同意 - GDPR 和 CCPA 要求在跟踪前取得用户的明确同意。应将同意管理纳入分析层,而不是事后补上。
- 少即是多 - 跟踪所有内容只会制造噪声。跟踪能够回答具体产品问题的事件即可。之后随时可以添加事件;清理现有数据中的噪声要困难得多。
关键模式
模式 1:事件分类设计
适用场景: 实施任何分析跟踪之前。这是其他所有工作的基础。
实现:
// Event taxonomy schema
// Convention: object_action (noun_verb in past tense)
// Core event types
type AnalyticsEvent =
// Authentication
| { event: "user_signed_up"; properties: { method: "email" | "google" | "github"; referralSource?: string } }
| { event: "user_logged_in"; properties: { method: "email" | "google" | "github" } }
| { event: "user_logged_out"; properties: Record<string, never> }
// Onboarding
| { event: "onboarding_started"; properties: { variant?: string } }
| { event: "onboarding_step_completed"; properties: { step: number; stepName: string } }
| { event: "onboarding_completed"; properties: { durationSeconds: number } }
| { event: "onboarding_skipped"; properties: { lastStep: number } }
// Core product actions
| { event: "project_created"; properties: { template?: string; source: "dashboard" | "onboarding" | "api" } }
| { event: "project_deleted"; properties: { projectAge: number; itemCount: number } }
| { event: "file_uploaded"; properties: { fileType: string; fileSizeBytes: number; source: "drag_drop" | "file_picker" | "api" } }
// Subscription
| { event: "subscription_started"; properties: { plan: string; billingCycle: "monthly" | "annual"; amount: number } }
| { event: "subscription_upgraded"; properties: { fromPlan: string; toPlan: string } }
| { event: "subscription_cancelled"; properties: { reason?: string; plan: string; tenureDays: number } }
// Feature engagement
| { event: "feature_used"; properties: { feature: string; context: string } }
| { event: "search_performed"; properties: { query: string; resultCount: number; source: string } }
| { event: "export_completed"; properties: { format: "csv" | "pdf" | "json"; itemCount: number } };
// Type-safe tracking function
function track<T extends AnalyticsEvent>(
event: T["event"],
properties: T["properties"]
): void {
// Implementation below
}
// Usage - fully typed, autocomplete works
track("project_created", {
template: "blank",
source: "dashboard",
});
原因: 类型化的事件分类体系可避免拼写错误(user_signedup 与 user_signed_up),确保始终包含必需属性,并让跟踪计划能够自我说明。object_action 约定可在分析仪表板中将相关事件归为一组。
模式 2:带同意管理的分析客户端
适用场景: 所有跟踪用户行为的产品,也就是所有产品。
实现:
// analytics.ts - Unified analytics client
import posthog from "posthog-js";
type ConsentStatus = "granted" | "denied" | "pending";
interface AnalyticsConfig {
posthogKey: string;
posthogHost?: string;
}
class Analytics {
private initialized = false;
private consent: ConsentStatus = "pending";
private queuedEvents: Array<{ event: string; properties: Record<string, unknown> }> = [];
init(config: AnalyticsConfig) {
posthog.init(config.posthogKey, {
api_host: config.posthogHost ?? "https://us.i.posthog.com",
persistence: "localStorage+cookie",
autocapture: false, // Explicit tracking only
capture_pageview: false, // Manual pageview tracking
capture_pageleave: true,
// Respect Do Not Track
respect_dnt: true,
// Cookie-less mode until consent
persistence: this.consent === "granted" ? "localStorage+cookie" : "memory",
});
this.initialized = true;
}
setConsent(status: ConsentStatus) {
this.consent = status;
if (status === "granted") {
posthog.opt_in_capturing();
// Flush queued events
for (const event of this.queuedEvents) {
this.trackInternal(event.event, event.properties);
}
this.queuedEvents = [];
} else if (status === "denied") {
posthog.opt_out_capturing();
this.queuedEvents = [];
}
}
identify(userId: string, traits?: Record<string, unknown>) {
if (this.consent !== "granted") return;
posthog.identify(userId, traits);
}
// Alias anonymous ID to authenticated ID (for signup flow)
alias(newId: string) {
if (this.consent !== "granted") return;
posthog.alias(newId);
}
track(event: string, properties?: Record<string, unknown>) {
if (this.consent === "denied") return;
const enrichedProperties = {
...properties,
timestamp: new Date().toISOString(),
url: typeof window !== "undefined" ? window.location.href : undefined,
referrer: typeof document !== "undefined" ? document.referrer : undefined,
};
if (this.consent === "pending") {
this.queuedEvents.push({ event, properties: enrichedProperties });
return;
}
this.trackInternal(event, enrichedProperties);
}
private trackInternal(event: string, properties: Record<string, unknown>) {
if (!this.initialized) return;
posthog.capture(event, properties);
}
page(name?: string, properties?: Record<string, unknown>) {
this.track("$pageview", { pageName: name, ...properties });
}
reset() {
posthog.reset();
}
}
export const analytics = new Analytics();
// React consent banner component
function ConsentBanner() {
const [showBanner, setShowBanner] = useState(() => {
return localStorage.getItem("analytics_consent") === null;
});
const handleConsent = (granted: boolean) => {
const status = granted ? "granted" : "denied";
localStorage.setItem("analytics_consent", status);
analytics.setConsent(status);
setShowBanner(false);
};
if (!showBanner) return null;
return (
<div role="dialog" aria-label="Cookie consent" className="consent-banner">
<p>We use analytics to improve our product. No personal data is sold.</p>
<div className="consent-actions">
<button onClick={() => handleConsent(false)}>Decline</button>
<button onClick={() => handleConsent(true)}>Accept</button>
</div>
</div>
);
}
原因: 先征得同意再进行分析是法律要求(GDPR、CCPA),也有助于建立用户信任。队列模式可确保用户在执行操作后才授予同意时,事件也不会丢失。明确跟踪(不自动捕获)能让数据保持干净、符合预期。
模式 3:漏斗分析实现
适用场景: 衡量用户在多步骤流程(注册、引导、结账)中的转化情况。
实现:
// Track each funnel step explicitly
const ONBOARDING_FUNNEL = [
"onboarding_started",
"onboarding_step_completed:profile",
"onboarding_step_completed:workspace",
"onboarding_step_completed:invite",
"onboarding_completed",
] as const;
// Instrument each step
function OnboardingFlow() {
const [currentStep, setCurrentStep] = useState(0);
useEffect(() => {
analytics.track("onboarding_started", { variant: "v2" });
}, []);
const completeStep = (stepName: string) => {
analytics.track("onboarding_step_completed", {
step: currentStep,
stepName,
timeOnStepSeconds: getTimeOnStep(),
});
setCurrentStep((prev) => prev + 1);
};
const skip = () => {
analytics.track("onboarding_skipped", {
lastStep: currentStep,
lastStepName: steps[currentStep].name,
});
router.push("/dashboard");
};
const complete = () => {
analytics.track("onboarding_completed", {
durationSeconds: getTotalDuration(),
stepsCompleted: currentStep + 1,
stepsSkipped: steps.length - currentStep - 1,
});
router.push("/dashboard");
};
// ...render steps
}
// Checkout funnel tracking
function useCheckoutFunnel() {
const trackStep = (step: string, properties?: Record<string, unknown>) => {
analytics.track(`checkout_${step}`, {
...properties,
cartValue: getCartTotal(),
itemCount: getCartItemCount(),
timestamp: Date.now(),
});
};
return {
viewCart: () => trackStep("cart_viewed"),
startCheckout: () => trackStep("started"),
addShipping: (method: string) => trackStep("shipping_added", { method }),
addPayment: (type: string) => trackStep("payment_added", { type }),
complete: (orderId: string) => trackStep("completed", { orderId }),
abandon: (step: string) => trackStep("abandoned", { lastStep: step }),
};
}
原因: 漏斗分析能揭示用户在哪一步流失。结合上下文跟踪每个步骤(耗时、变体、购物车金额),即可进行细分分析:“来自 Google Ads 的用户在配送步骤的流失率是自然流量用户的 3 倍。”这一洞察有助于开展有针对性的优化。
模式 4:由功能标志驱动的 A/B 测试
适用场景: 在向所有用户推出产品变更之前,以严谨的统计方法进行测试。
实现:
// PostHog feature flags for A/B testing
import posthog from "posthog-js";
// Check feature flag with typed variants
function useExperiment<T extends string>(
flagKey: string,
variants: T[]
): T | "control" | undefined {
const [variant, setVariant] = useState<T | "control" | undefined>();
useEffect(() => {
posthog.onFeatureFlags(() => {
const value = posthog.getFeatureFlag(flagKey);
if (value === false || value === undefined) {
setVariant("control");
} else if (typeof value === "string" && variants.includes(value as T)) {
setVariant(value as T);
} else {
setVariant("control");
}
// Track experiment exposure (for accurate analysis)
analytics.track("$experiment_started", {
experiment: flagKey,
variant: value ?? "control",
});
});
}, [flagKey]);
return variant;
}
// Usage in component
function PricingPage() {
const variant = useExperiment("pricing-page-redesign", ["new-layout", "social-proof"]);
if (!variant) return <LoadingSkeleton />;
switch (variant) {
case "new-layout":
return <PricingNewLayout />;
case "social-proof":
return <PricingSocialProof />;
case "control":
default:
return <PricingControl />;
}
}
原因: A/B 测试可让产品决策摆脱主观判断。功能标志支持逐步推出、即时回滚和针对特定细分群体进行定向。将曝光事件与转化事件分开跟踪,可确保统计分析准确(意向治疗分析)。
事件命名规范参考
| 规范 | 示例 | 适用场景 |
|---|---|---|
object_action | project_created、file_uploaded | 标准产品事件 |
$system_event | $pageview、$identify | 系统/平台事件 |
experiment_* | $experiment_started | A/B 测试跟踪 |
feature_used | feature_used { feature: "export" } | 通用功能使用情况 |
反模式
| 反模式 | 问题所在 | 更好的做法 |
|---|---|---|
| 自动捕获所有数据 | 数据嘈杂、难以查询,且存在隐私风险 | 使用定义明确的分类体系显式跟踪事件 |
| 事件名称不一致 | userSignedUp、user_signed_up 和 signup 混用 | 使用 TypeScript 类型强制执行命名规范 |
| 未经同意就跟踪 | 违反 GDPR/CCPA,罚款最高可达收入的 4% | 使用带队列模式的同意横幅 |
| 未识别用户身份 | 无法进行群组分析或留存分析 | 用户登录时识别用户,注册时设置别名 |
| 在事件属性中跟踪 PII | 侵犯隐私,导致数据保留问题 | 使用用户 ID,不要在事件属性中使用电子邮件地址或姓名 |
使用一个庞大的 "user_action" 事件 | 无法创建有意义的漏斗 | 为每个有意义的操作设置专属事件 |
| 未跟踪负面结果 | 只能看到哪些做法有效,看不到哪些无效 | 跟踪错误、放弃行为和愤怒点击 |
检查清单
- 已记录事件分类体系并定义类型(TypeScript 接口)
- 已强制执行命名规范(
object_action模式) - 已初始化并集成同意管理的分析客户端
- 用户登录时识别用户,注册时设置别名
- 已使用上下文属性跟踪漏斗步骤
- 已设置功能标志以进行 A/B 测试
- 分别跟踪实验曝光事件和转化事件
- 已使用队列模式实现 GDPR 同意横幅
- 事件属性中不包含 PII(电子邮件地址、全名、IP)
- 已在分析仪表板中可视化关键漏斗
- 已配置留存群组(第 1 天、第 7 天、第 30 天)
- 已在开发环境中验证分析事件(调试模式)
相关资源
- 技能:
growth-engineering(A/B 测试基础设施)、authentication-patterns(识别用户/设置别名流程) - 技能:
accessibility-a11y(无障碍同意横幅) - 规则:
docs/reference/stacks/react-typescript.md(用于分析的 React Hooks)