feat: add product analytics skill with metrics calculator
This commit is contained in:
107
product-team/product-analytics/SKILL.md
Normal file
107
product-team/product-analytics/SKILL.md
Normal file
@@ -0,0 +1,107 @@
|
||||
---
|
||||
name: product-analytics
|
||||
description: Use when defining product KPIs, building metric dashboards, running cohort or retention analysis, or interpreting feature adoption trends across product stages.
|
||||
---
|
||||
|
||||
# Product Analytics
|
||||
|
||||
Define, track, and interpret product metrics across discovery, growth, and mature product stages.
|
||||
|
||||
## When To Use
|
||||
|
||||
Use this skill for:
|
||||
- Metric framework selection (AARRR, North Star, HEART)
|
||||
- KPI definition by product stage (pre-PMF, growth, mature)
|
||||
- Dashboard design and metric hierarchy
|
||||
- Cohort and retention analysis
|
||||
- Feature adoption and funnel interpretation
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Select metric framework
|
||||
- AARRR for growth loops and funnel visibility
|
||||
- North Star for cross-functional strategic alignment
|
||||
- HEART for UX quality and user experience measurement
|
||||
|
||||
2. Define stage-appropriate KPIs
|
||||
- Pre-PMF: activation, early retention, qualitative success
|
||||
- Growth: acquisition efficiency, expansion, conversion velocity
|
||||
- Mature: retention depth, revenue quality, operational efficiency
|
||||
|
||||
3. Design dashboard layers
|
||||
- Executive layer: 5-7 directional metrics
|
||||
- Product health layer: acquisition, activation, retention, engagement
|
||||
- Feature layer: adoption, depth, repeat usage, outcome correlation
|
||||
|
||||
4. Run cohort + retention analysis
|
||||
- Segment by signup cohort or feature exposure cohort
|
||||
- Compare retention curves, not single-point snapshots
|
||||
- Identify inflection points around onboarding and first value moment
|
||||
|
||||
5. Interpret and act
|
||||
- Connect metric movement to product changes and release timeline
|
||||
- Distinguish signal from noise using period-over-period context
|
||||
- Propose one clear product action per major metric risk/opportunity
|
||||
|
||||
## KPI Guidance By Stage
|
||||
|
||||
### Pre-PMF
|
||||
- Activation rate
|
||||
- Week-1 retention
|
||||
- Time-to-first-value
|
||||
- Problem-solution fit interview score
|
||||
|
||||
### Growth
|
||||
- Funnel conversion by stage
|
||||
- Monthly retained users
|
||||
- Feature adoption among new cohorts
|
||||
- Expansion / upsell proxy metrics
|
||||
|
||||
### Mature
|
||||
- Net revenue retention aligned product metrics
|
||||
- Power-user share and depth of use
|
||||
- Churn risk indicators by segment
|
||||
- Reliability and support-deflection product metrics
|
||||
|
||||
## Dashboard Design Principles
|
||||
|
||||
- Show trends, not isolated point estimates.
|
||||
- Keep one owner per KPI.
|
||||
- Pair each KPI with target, threshold, and decision rule.
|
||||
- Use cohort and segment filters by default.
|
||||
- Prefer comparable time windows (weekly vs weekly, monthly vs monthly).
|
||||
|
||||
See:
|
||||
- `references/metrics-frameworks.md`
|
||||
- `references/dashboard-templates.md`
|
||||
|
||||
## Cohort Analysis Method
|
||||
|
||||
1. Define cohort anchor event (signup, activation, first purchase).
|
||||
2. Define retained behavior (active day, key action, repeat session).
|
||||
3. Build retention matrix by cohort week/month and age period.
|
||||
4. Compare curve shape across cohorts.
|
||||
5. Flag early drop points and investigate journey friction.
|
||||
|
||||
## Retention Curve Interpretation
|
||||
|
||||
- Sharp early drop, low plateau: onboarding mismatch or weak initial value.
|
||||
- Moderate drop, stable plateau: healthy core audience with predictable churn.
|
||||
- Flattening at low level: product used occasionally, revisit value metric.
|
||||
- Improving newer cohorts: onboarding or positioning improvements are working.
|
||||
|
||||
## Tooling
|
||||
|
||||
### `scripts/metrics_calculator.py`
|
||||
|
||||
CLI utility for:
|
||||
- Retention rate calculations by cohort age
|
||||
- Cohort table generation
|
||||
- Basic funnel conversion analysis
|
||||
|
||||
Examples:
|
||||
```bash
|
||||
python3 scripts/metrics_calculator.py retention events.csv
|
||||
python3 scripts/metrics_calculator.py cohort events.csv --cohort-grain month
|
||||
python3 scripts/metrics_calculator.py funnel funnel.csv --stages visit,signup,activate,pay
|
||||
```
|
||||
@@ -0,0 +1,66 @@
|
||||
# Dashboard Templates
|
||||
|
||||
## 1. Executive Dashboard Template
|
||||
|
||||
Purpose: quick company-level product signal for leadership.
|
||||
|
||||
Sections:
|
||||
1. North Star trend (current, target, trailing 12 periods)
|
||||
2. Growth summary (new users/accounts, activation)
|
||||
3. Retention summary (short-term + medium-term cohorts)
|
||||
4. Revenue-linked product indicators
|
||||
5. Risks and actions
|
||||
|
||||
Suggested KPI block:
|
||||
|
||||
| KPI | Current | Target | Delta | Owner | Action |
|
||||
|---|---:|---:|---:|---|---|
|
||||
| North Star | | | | | |
|
||||
| Activation Rate | | | | | |
|
||||
| W8 Retention | | | | | |
|
||||
| Paid Conversion | | | | | |
|
||||
|
||||
## 2. Product Health Dashboard Template
|
||||
|
||||
Purpose: monitor full user journey and detect bottlenecks.
|
||||
|
||||
Sections:
|
||||
1. Acquisition funnel by channel/segment
|
||||
2. Activation funnel with drop-off points
|
||||
3. Cohort retention matrix + curve chart
|
||||
4. Feature adoption distribution
|
||||
5. Reliability metrics tied to user outcomes
|
||||
|
||||
Recommended views:
|
||||
- Weekly cohort retention heatmap
|
||||
- Funnel stage conversion waterfall
|
||||
- Segment comparison (SMB vs enterprise)
|
||||
- New vs returning user behavior split
|
||||
|
||||
## 3. Feature Adoption Dashboard Template
|
||||
|
||||
Purpose: evaluate feature launch quality and ongoing usage.
|
||||
|
||||
Sections:
|
||||
1. Exposure and eligibility count
|
||||
2. First-use adoption rate
|
||||
3. Repeat usage rate (2nd, 3rd, nth use)
|
||||
4. Time-to-adoption from signup/activation
|
||||
5. Impact on primary outcomes (retention, conversion)
|
||||
|
||||
Adoption KPI examples:
|
||||
|
||||
| Metric | Definition |
|
||||
|---|---|
|
||||
| First-use adoption | Users who used feature at least once / eligible users |
|
||||
| Repeat adoption | Users with 2+ uses / users with first use |
|
||||
| Sustained adoption | Users with usage in 3 of last 4 weeks |
|
||||
| Time to adoption | Median days from eligibility to first use |
|
||||
|
||||
## Dashboard Design Rules
|
||||
|
||||
- Keep each dashboard to one decision horizon (weekly ops vs quarterly strategy).
|
||||
- Always annotate major product releases on charts.
|
||||
- Add threshold bands for risk detection.
|
||||
- Show metric definitions next to charts.
|
||||
- Include a short "what changed" narrative block.
|
||||
@@ -0,0 +1,84 @@
|
||||
# Metrics Frameworks
|
||||
|
||||
## AARRR (Pirate Metrics)
|
||||
|
||||
AARRR breaks the product journey into five stages.
|
||||
|
||||
1. Acquisition
|
||||
- How users discover the product
|
||||
- Example metrics: signups, CAC, channel conversion
|
||||
|
||||
2. Activation
|
||||
- First meaningful value moment
|
||||
- Example metrics: activation rate, time-to-first-value
|
||||
|
||||
3. Retention
|
||||
- Ongoing user return behavior
|
||||
- Example metrics: D7/W4 retention, rolling retained users
|
||||
|
||||
4. Revenue
|
||||
- Monetization and value capture
|
||||
- Example metrics: conversion to paid, ARPU, expansion revenue
|
||||
|
||||
5. Referral
|
||||
- Organic growth from existing users
|
||||
- Example metrics: referral rate, invite conversion, K-factor
|
||||
|
||||
## North Star Metric Framework
|
||||
|
||||
North Star = metric capturing long-term customer value delivered.
|
||||
|
||||
### North Star Criteria
|
||||
- Reflects real user value
|
||||
- Sensitive to product improvements
|
||||
- Predictive of sustainable growth
|
||||
- Understandable across functions
|
||||
|
||||
### Example North Star Metrics
|
||||
- Collaboration SaaS: weekly active teams
|
||||
- Marketplace: successful transactions per active buyer
|
||||
- Content product: hours of qualified consumption
|
||||
|
||||
### Input Metrics
|
||||
Track levers that influence the North Star:
|
||||
- Acquisition quality
|
||||
- Activation quality
|
||||
- Engagement depth
|
||||
- Retention durability
|
||||
|
||||
## HEART Framework
|
||||
|
||||
HEART is a UX-oriented framework from Google.
|
||||
|
||||
- Happiness: satisfaction, NPS, perceived quality
|
||||
- Engagement: interaction depth/frequency
|
||||
- Adoption: first-time use of features/products
|
||||
- Retention: return behavior over time
|
||||
- Task Success: completion rate, error rate, time on task
|
||||
|
||||
### HEART + Goals-Signals-Metrics
|
||||
1. Goals: what UX outcome you want
|
||||
2. Signals: observed behavior indicating movement
|
||||
3. Metrics: measurable indicator for each signal
|
||||
|
||||
## Framework Selection Guide
|
||||
|
||||
| Situation | Recommended Framework |
|
||||
|---|---|
|
||||
| Early growth and funnel bottlenecks | AARRR |
|
||||
| Company-wide strategic alignment | North Star |
|
||||
| UX and product quality optimization | HEART |
|
||||
| Mixed maturity org | North Star + AARRR operational layers |
|
||||
|
||||
## Example: B2B SaaS Product
|
||||
|
||||
- North Star: weekly active accounts completing core workflow
|
||||
- AARRR operational metrics:
|
||||
- Acquisition: qualified signups
|
||||
- Activation: % accounts completing setup in 7 days
|
||||
- Retention: W8 retained accounts
|
||||
- Revenue: paid conversion and expansion rate
|
||||
- Referral: invited teammate activation rate
|
||||
- HEART for onboarding redesign:
|
||||
- Task Success: onboarding completion rate
|
||||
- Happiness: onboarding CSAT
|
||||
155
product-team/product-analytics/scripts/metrics_calculator.py
Executable file
155
product-team/product-analytics/scripts/metrics_calculator.py
Executable file
@@ -0,0 +1,155 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Product metrics calculator: retention, cohort matrix, and funnel conversion."""
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
import datetime as dt
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
def parse_date(value: str) -> dt.date:
|
||||
return dt.date.fromisoformat(value.strip()[:10])
|
||||
|
||||
|
||||
def load_csv(path: str):
|
||||
with open(path, "r", encoding="utf-8", newline="") as handle:
|
||||
return list(csv.DictReader(handle))
|
||||
|
||||
|
||||
def retention(args: argparse.Namespace) -> int:
|
||||
rows = load_csv(args.input)
|
||||
cohorts = {}
|
||||
activity = defaultdict(set)
|
||||
|
||||
for row in rows:
|
||||
user = row[args.user_column].strip()
|
||||
cohort_date = parse_date(row[args.cohort_column])
|
||||
activity_date = parse_date(row[args.activity_column])
|
||||
cohorts[user] = min(cohorts.get(user, cohort_date), cohort_date)
|
||||
delta = (activity_date - cohorts[user]).days
|
||||
if delta >= 0:
|
||||
activity[delta].add(user)
|
||||
|
||||
base_users = len(cohorts)
|
||||
if base_users == 0:
|
||||
print("No users found.")
|
||||
return 1
|
||||
|
||||
print("Retention by period")
|
||||
print("period,active_users,retention_rate")
|
||||
max_period = args.max_period
|
||||
for period in range(0, max_period + 1):
|
||||
users = len(activity.get(period, set()))
|
||||
rate = users / base_users
|
||||
print(f"{period},{users},{rate:.4f}")
|
||||
return 0
|
||||
|
||||
|
||||
def cohort(args: argparse.Namespace) -> int:
|
||||
rows = load_csv(args.input)
|
||||
cohorts = {}
|
||||
activity = defaultdict(set)
|
||||
|
||||
for row in rows:
|
||||
user = row[args.user_column].strip()
|
||||
cohort_date = parse_date(row[args.cohort_column])
|
||||
activity_date = parse_date(row[args.activity_column])
|
||||
|
||||
if args.cohort_grain == "month":
|
||||
cohort_key = cohort_date.strftime("%Y-%m")
|
||||
else:
|
||||
cohort_key = f"{cohort_date.isocalendar().year}-W{cohort_date.isocalendar().week:02d}"
|
||||
|
||||
cohorts.setdefault(user, cohort_key)
|
||||
age = (activity_date - cohort_date).days
|
||||
if age >= 0:
|
||||
activity[(cohort_key, age)].add(user)
|
||||
|
||||
cohort_sizes = defaultdict(int)
|
||||
for cohort_key in cohorts.values():
|
||||
cohort_sizes[cohort_key] += 1
|
||||
|
||||
cohort_keys = sorted(cohort_sizes.keys())
|
||||
print("cohort,age_days,active_users,cohort_size,retention_rate")
|
||||
for cohort_key in cohort_keys:
|
||||
size = cohort_sizes[cohort_key]
|
||||
for age in range(0, args.max_period + 1):
|
||||
active_users = len(activity.get((cohort_key, age), set()))
|
||||
rate = (active_users / size) if size else 0
|
||||
print(f"{cohort_key},{age},{active_users},{size},{rate:.4f}")
|
||||
return 0
|
||||
|
||||
|
||||
def funnel(args: argparse.Namespace) -> int:
|
||||
rows = load_csv(args.input)
|
||||
stages = [item.strip() for item in args.stages.split(",") if item.strip()]
|
||||
if not stages:
|
||||
print("No stages provided.")
|
||||
return 1
|
||||
|
||||
stage_users = {stage: set() for stage in stages}
|
||||
for row in rows:
|
||||
user = row[args.user_column].strip()
|
||||
stage = row[args.stage_column].strip()
|
||||
if stage in stage_users:
|
||||
stage_users[stage].add(user)
|
||||
|
||||
print("stage,users,conversion_from_previous,conversion_from_first")
|
||||
previous_count = None
|
||||
first_count = None
|
||||
for stage in stages:
|
||||
count = len(stage_users[stage])
|
||||
if first_count is None:
|
||||
first_count = count
|
||||
conv_prev = (count / previous_count) if previous_count else 1.0
|
||||
conv_first = (count / first_count) if first_count else 0
|
||||
print(f"{stage},{count},{conv_prev:.4f},{conv_first:.4f}")
|
||||
previous_count = count
|
||||
return 0
|
||||
|
||||
|
||||
def build_parser() -> argparse.ArgumentParser:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Calculate retention, cohort, and funnel metrics from CSV data."
|
||||
)
|
||||
subparsers = parser.add_subparsers(dest="command", required=True)
|
||||
|
||||
common = {
|
||||
"help": "CSV input path",
|
||||
}
|
||||
|
||||
retention_parser = subparsers.add_parser("retention", help="Calculate retention by day.")
|
||||
retention_parser.add_argument("input", **common)
|
||||
retention_parser.add_argument("--user-column", default="user_id")
|
||||
retention_parser.add_argument("--cohort-column", default="cohort_date")
|
||||
retention_parser.add_argument("--activity-column", default="activity_date")
|
||||
retention_parser.add_argument("--max-period", type=int, default=30)
|
||||
retention_parser.set_defaults(func=retention)
|
||||
|
||||
cohort_parser = subparsers.add_parser("cohort", help="Build cohort retention matrix rows.")
|
||||
cohort_parser.add_argument("input", **common)
|
||||
cohort_parser.add_argument("--user-column", default="user_id")
|
||||
cohort_parser.add_argument("--cohort-column", default="cohort_date")
|
||||
cohort_parser.add_argument("--activity-column", default="activity_date")
|
||||
cohort_parser.add_argument("--cohort-grain", choices=["week", "month"], default="week")
|
||||
cohort_parser.add_argument("--max-period", type=int, default=30)
|
||||
cohort_parser.set_defaults(func=cohort)
|
||||
|
||||
funnel_parser = subparsers.add_parser("funnel", help="Calculate funnel conversion by stage.")
|
||||
funnel_parser.add_argument("input", **common)
|
||||
funnel_parser.add_argument("--user-column", default="user_id")
|
||||
funnel_parser.add_argument("--stage-column", default="stage")
|
||||
funnel_parser.add_argument("--stages", required=True)
|
||||
funnel_parser.set_defaults(func=funnel)
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = build_parser()
|
||||
args = parser.parse_args()
|
||||
return args.func(args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user