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
- 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
- Define stage-appropriate KPIs
- Pre-PMF: activation, early retention, qualitative success
- Growth: acquisition efficiency, expansion, conversion velocity
- Mature: retention depth, revenue quality, operational efficiency
- Design dashboard layers
- Executive layer: 5-7 directional metrics
- Product health layer: acquisition, activation, retention, engagement
- Feature layer: adoption, depth, repeat usage, outcome correlation
- 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
- 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
- Define cohort anchor event (signup, activation, first purchase).
- Define retained behavior (active day, key action, repeat session).
- Build retention matrix by cohort week/month and age period.
- Compare curve shape across cohorts.
- 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.
scripts/metrics_calculator.py
CLI utility for:
- Retention rate calculations by cohort age
- Cohort table generation
- Basic funnel conversion analysis
Examples:
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
Dashboard Templates
1. Executive Dashboard Template
Purpose: quick company-level product signal for leadership.
Sections:
- North Star trend (current, target, trailing 12 periods)
- Growth summary (new users/accounts, activation)
- Retention summary (short-term + medium-term cohorts)
- Revenue-linked product indicators
- 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:
- Acquisition funnel by channel/segment
- Activation funnel with drop-off points
- Cohort retention matrix + curve chart
- Feature adoption distribution
- 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:
- Exposure and eligibility count
- First-use adoption rate
- Repeat usage rate (2nd, 3rd, nth use)
- Time-to-adoption from signup/activation
- 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.
Metrics Frameworks
AARRR (Pirate Metrics)
AARRR breaks the product journey into five stages.
- Acquisition
- How users discover the product
- Example metrics: signups, CAC, channel conversion
- Activation
- First meaningful value moment
- Example metrics: activation rate, time-to-first-value
- Retention
- Ongoing user return behavior
- Example metrics: D7/W4 retention, rolling retained users
- Revenue
- Monetization and value capture
- Example metrics: conversion to paid, ARPU, expansion revenue
- 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
- Goals: what UX outcome you want
- Signals: observed behavior indicating movement
- 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
#!/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())