DEV Community

Thesius Code
Thesius Code

Posted on • Originally published at datanest-stores.pages.dev

Business Metrics Handbook

Business Metrics Handbook

Definitive reference for SaaS, e-commerce, and marketplace metrics. Every metric includes a precise definition, SQL formula, Python calculation, industry benchmarks, and common pitfalls. Stop debating metric definitions — standardize on this.

Key Features

  • 60+ Metric Definitions — organized by domain: SaaS, e-commerce, marketplace, product, marketing
  • SQL Formulas — copy-paste queries for every metric against standard schema
  • Python Calculators — reusable functions with type hints and docstrings
  • Industry Benchmarks — percentile tables (25th/50th/75th/90th) by company stage
  • Metric Trees — visual decomposition showing how metrics relate (e.g., Revenue = Users × ARPU)
  • Anti-Patterns — common calculation mistakes and how to avoid them
  • Executive Dashboard Spec — recommended metric sets for board decks by business model

Quick Start

from src.saas_metrics import calculate_mrr, calculate_churn, calculate_ltv

# Monthly recurring revenue from subscription data
mrr = calculate_mrr(subscriptions=subscriptions_df, as_of="2025-12-31")
print(f"MRR: ${mrr:,.2f}")

# Logo churn rate
churn = calculate_churn(
    start_customers=1200,
    end_customers=1150,
    new_customers=80,
)
print(f"Monthly churn: {churn:.2%}")  # 10.83%

# LTV using churn-based method
ltv = calculate_ltv(arpu=85.00, monthly_churn_rate=churn)
print(f"LTV: ${ltv:,.2f}")  # $784.95
Enter fullscreen mode Exit fullscreen mode

Usage Examples

SaaS: Net Revenue Retention (NRR)

-- Net Revenue Retention: expansion + contraction + churn
WITH period AS (
    SELECT
        DATE_TRUNC('month', period_start) AS month,
        SUM(CASE WHEN cohort_month < DATE_TRUNC('month', period_start)
                 THEN mrr_start END) AS beginning_mrr,
        SUM(CASE WHEN expansion_mrr > 0
                 THEN expansion_mrr ELSE 0 END) AS expansion,
        SUM(CASE WHEN contraction_mrr < 0
                 THEN contraction_mrr ELSE 0 END) AS contraction,
        SUM(CASE WHEN churned = TRUE
                 THEN mrr_start ELSE 0 END) AS churned_mrr
    FROM mrr_movements
    GROUP BY 1
)
SELECT
    month,
    ROUND((beginning_mrr + expansion + contraction - churned_mrr)
          / NULLIF(beginning_mrr, 0) * 100, 1) AS nrr_pct
FROM period
ORDER BY month;
-- Benchmark: >100% is good, >120% is elite for B2B SaaS
Enter fullscreen mode Exit fullscreen mode

E-Commerce: CAC Payback

def cac_payback_months(cac: float, avg_monthly_revenue: float,
                       gross_margin: float) -> float:
    """Calculate months to recover customer acquisition cost.

    Args:
        cac: Total acquisition cost per customer.
        avg_monthly_revenue: Average monthly revenue per customer.
        gross_margin: Gross margin as a decimal (e.g., 0.65).

    Returns:
        Number of months to payback. Target: <12 months.
    """
    monthly_gross_profit = avg_monthly_revenue * gross_margin
    return cac / monthly_gross_profit

# $150 CAC, $45/mo revenue, 65% margin → 5.1 months payback
print(cac_payback_months(150, 45, 0.65))
Enter fullscreen mode Exit fullscreen mode

Marketplace: Take Rate and GMV

SELECT
    category,
    SUM(gmv) AS total_gmv,
    SUM(platform_revenue) AS total_revenue,
    ROUND(SUM(platform_revenue) / NULLIF(SUM(gmv), 0) * 100, 2)
        AS take_rate_pct
FROM transactions
WHERE transaction_date >= DATE_TRUNC('quarter', CURRENT_DATE)
GROUP BY category
ORDER BY total_gmv DESC;
-- Benchmark: 10-20% managed marketplaces, 3-8% open marketplaces
Enter fullscreen mode Exit fullscreen mode

Metric Benchmarks (SaaS)

Metric 25th Pctile Median 75th Pctile 90th Pctile
Monthly Churn 5.0% 3.5% 2.0% 1.0%
Net Revenue Retention 95% 105% 115% 130%
CAC Payback (months) 18 12 8 5
Gross Margin 60% 70% 78% 85%
LTV:CAC Ratio 2.0x 3.0x 5.0x 8.0x
Rule of 40 Score 15% 30% 45% 60%

Configuration

# config.example.yaml
business_model: "saas"          # saas | ecommerce | marketplace
currency: "USD"
fiscal_year_start: "01-01"      # MM-DD

saas:
  contract_basis: "monthly"     # monthly | annual | mixed
  include_usage_revenue: true   # Include metered billing in MRR
  expansion_threshold: 0.0      # Min $ change to count as expansion

ecommerce:
  attribution_window_days: 30   # For CAC calculations
  return_window_days: 30        # Exclude returns within window
Enter fullscreen mode Exit fullscreen mode

Best Practices

  1. Define metrics once, centrally — disagreements on "how we count churn" waste weeks
  2. Separate logo churn from revenue churn — they tell different stories
  3. Use cohorted metrics — blended averages hide trends
  4. Lag indicators need lead indicators — pair churn with engagement scores
  5. Benchmark against your stage — Series A benchmarks are irrelevant at Series C

Troubleshooting

Issue Cause Fix
MRR doesn't match accounting Deferred vs. recognized revenue MRR is a SaaS metric, not GAAP; reconcile separately
Churn rate >100% monthly Including downgrades in churn Separate churn (logo lost) from contraction (downgrade)
LTV seems impossibly high Using revenue not gross profit LTV = ARPU × Gross Margin / Churn Rate
CAC varies wildly by month Small sample + lumpy ad spend Use trailing 3-month average

This is 1 of 11 resources in the Data Analyst Toolkit toolkit. Get the complete [Business Metrics Handbook] with all files, templates, and documentation for $25.

Get the Full Kit →

Or grab the entire Data Analyst Toolkit bundle (11 products) for $129 — save 30%.

Get the Complete Bundle →


Related Articles

Top comments (0)