Customer Health Score
Composite metric that predicts customer retention risk and expansion opportunity
Overview
Customer Health Score is a composite metric that combines multiple data points to predict customer retention risk and identify expansion opportunities. This predictive indicator helps customer success teams prioritize interventions, reduce churn, and drive growth within the existing customer base.
The score typically incorporates product usage patterns, engagement levels, support interactions, payment history, and feature adoption to create a holistic view of customer satisfaction and business value.
Health Score = Weighted Sum of (Usage Score + Engagement Score + Support Score + Business Value Score)
90-100
Excellent Health
Expansion Ready70-89
Healthy
Stable & Engaged40-69
At Risk
Needs Attention0-39
Critical
Immediate InterventionUsage Score
Product adoption & activity
Engagement Score
Feature usage & depth
Support Score
Ticket volume & satisfaction
Business Value
Revenue & growth potential
Predictive Power
Health scores are most effective when combined with machine learning models that identify patterns and predict outcomes, rather than simple weighted averages.
Why It Matters
- Churn Prevention: Identifies at-risk customers before they cancel
- Resource Allocation: Helps prioritize customer success efforts
- Expansion Opportunities: Highlights customers ready for upselling
- Proactive Intervention: Enables early warning system for issues
- Revenue Protection: Preserves and grows recurring revenue
- Customer Experience: Improves overall customer satisfaction
How to Measure It
Calculate customer health scores by combining usage patterns, engagement metrics, support interactions, and business indicators with appropriate weightings and scoring algorithms.
Basic Health Score Calculation
-- Calculate comprehensive customer health scores
WITH customer_usage_metrics AS (
SELECT
customer_id,
DATE_TRUNC('month', event_date) as month,
COUNT(DISTINCT DATE(event_date)) as active_days,
COUNT(*) as total_events,
COUNT(DISTINCT feature_used) as features_used,
AVG(session_duration_minutes) as avg_session_duration,
COUNT(DISTINCT user_id) as active_users_count
FROM customer_product_usage
WHERE event_date >= CURRENT_DATE - INTERVAL '90 days'
GROUP BY 1, 2
),
customer_engagement_metrics AS (
SELECT
customer_id,
DATE_TRUNC('month', event_date) as month,
COUNT(CASE WHEN event_type = 'feature_discovery' THEN 1 END) as new_features_tried,
COUNT(CASE WHEN event_type = 'advanced_action' THEN 1 END) as advanced_actions,
COUNT(CASE WHEN event_type = 'collaboration' THEN 1 END) as collaboration_events,
COUNT(CASE WHEN event_type = 'content_creation' THEN 1 END) as content_created
FROM customer_engagement_events
WHERE event_date >= CURRENT_DATE - INTERVAL '90 days'
GROUP BY 1, 2
),
customer_support_metrics AS (
SELECT
customer_id,
DATE_TRUNC('month', created_date) as month,
COUNT(*) as support_tickets,
COUNT(CASE WHEN priority = 'high' OR priority = 'critical' THEN 1 END) as high_priority_tickets,
AVG(resolution_time_hours) as avg_resolution_time,
AVG(customer_satisfaction_score) as avg_csat,
COUNT(CASE WHEN ticket_type = 'bug' THEN 1 END) as bug_reports
FROM customer_support_tickets
WHERE created_date >= CURRENT_DATE - INTERVAL '90 days'
GROUP BY 1, 2
),
customer_business_metrics AS (
SELECT
customer_id,
DATE_TRUNC('month', transaction_date) as month,
SUM(revenue) as monthly_revenue,
COUNT(DISTINCT invoice_id) as invoices_count,
AVG(EXTRACT(days FROM AGE(payment_date, invoice_date))) as avg_payment_delay,
COUNT(CASE WHEN payment_status = 'failed' THEN 1 END) as failed_payments
FROM customer_billing
WHERE transaction_date >= CURRENT_DATE - INTERVAL '90 days'
GROUP BY 1, 2
),
health_score_calculation AS (
SELECT
COALESCE(cum.customer_id, cem.customer_id, csm.customer_id, cbm.customer_id) as customer_id,
COALESCE(cum.month, cem.month, csm.month, cbm.month) as month,
-- Usage Score (0-25 points)
LEAST(25,
COALESCE(cum.active_days, 0) * 0.8 +
COALESCE(cum.features_used, 0) * 2 +
COALESCE(cum.active_users_count, 0) * 1.5
) as usage_score,
-- Engagement Score (0-25 points)
LEAST(25,
COALESCE(cem.new_features_tried, 0) * 3 +
COALESCE(cem.advanced_actions, 0) * 0.5 +
COALESCE(cem.collaboration_events, 0) * 0.3 +
COALESCE(cem.content_created, 0) * 0.2
) as engagement_score,
-- Support Score (0-25 points, inverted - fewer tickets = higher score)
GREATEST(0, 25 -
COALESCE(csm.support_tickets, 0) * 2 -
COALESCE(csm.high_priority_tickets, 0) * 5 -
COALESCE(csm.bug_reports, 0) * 3 +
COALESCE(csm.avg_csat, 3) * 3
) as support_score,
-- Business Value Score (0-25 points)
LEAST(25,
COALESCE(cbm.monthly_revenue, 0) / 1000 * 2 +
GREATEST(0, 10 - COALESCE(cbm.avg_payment_delay, 0)) * 1.5 -
COALESCE(cbm.failed_payments, 0) * 5
) as business_value_score,
-- Component metrics for analysis
cum.active_days,
cum.features_used,
cem.new_features_tried,
csm.support_tickets,
csm.avg_csat,
cbm.monthly_revenue
FROM customer_usage_metrics cum
FULL OUTER JOIN customer_engagement_metrics cem ON cum.customer_id = cem.customer_id AND cum.month = cem.month
FULL OUTER JOIN customer_support_metrics csm ON cum.customer_id = csm.customer_id AND cum.month = csm.month
FULL OUTER JOIN customer_business_metrics cbm ON cum.customer_id = cbm.customer_id AND cum.month = cbm.month
)
SELECT
customer_id,
month,
usage_score,
engagement_score,
support_score,
business_value_score,
ROUND(usage_score + engagement_score + support_score + business_value_score, 1) as total_health_score,
CASE
WHEN (usage_score + engagement_score + support_score + business_value_score) >= 90 THEN 'Excellent'
WHEN (usage_score + engagement_score + support_score + business_value_score) >= 70 THEN 'Healthy'
WHEN (usage_score + engagement_score + support_score + business_value_score) >= 40 THEN 'At Risk'
ELSE 'Critical'
END as health_category,
active_days,
features_used,
support_tickets,
monthly_revenue
FROM health_score_calculation
ORDER BY month DESC, total_health_score DESC;
Predictive Health Scoring
-- Advanced health scoring with trend analysis and predictive elements
WITH historical_health_scores AS (
SELECT
customer_id,
month,
total_health_score,
LAG(total_health_score, 1) OVER (PARTITION BY customer_id ORDER BY month) as prev_month_score,
LAG(total_health_score, 3) OVER (PARTITION BY customer_id ORDER BY month) as three_months_ago_score,
CASE WHEN next_month_revenue IS NOT NULL THEN 1 ELSE 0 END as retained_next_month
FROM customer_health_scores chs
LEFT JOIN customer_billing cb ON chs.customer_id = cb.customer_id
AND cb.transaction_date >= chs.month + INTERVAL '1 month'
AND cb.transaction_date < chs.month + INTERVAL '2 months'
),
trend_analysis AS (
SELECT
customer_id,
month,
total_health_score,
prev_month_score,
three_months_ago_score,
retained_next_month,
COALESCE(total_health_score - prev_month_score, 0) as month_over_month_change,
COALESCE(total_health_score - three_months_ago_score, 0) as three_month_trend,
CASE
WHEN prev_month_score IS NOT NULL THEN
CASE
WHEN total_health_score > prev_month_score THEN 'Improving'
WHEN total_health_score < prev_month_score THEN 'Declining'
ELSE 'Stable'
END
ELSE 'New Customer'
END as trend_direction
FROM historical_health_scores
),
risk_indicators AS (
SELECT
ta.*,
CASE
WHEN total_health_score < 40 THEN 'High Risk'
WHEN total_health_score < 70 AND trend_direction = 'Declining' THEN 'Medium Risk'
WHEN month_over_month_change < -10 THEN 'Trend Risk'
WHEN total_health_score >= 90 AND trend_direction = 'Improving' THEN 'Expansion Opportunity'
ELSE 'Low Risk'
END as risk_category,
CASE
WHEN total_health_score < 30 THEN 'Immediate'
WHEN total_health_score < 50 OR month_over_month_change < -15 THEN 'This Week'
WHEN total_health_score < 70 OR month_over_month_change < -10 THEN 'This Month'
ELSE 'Monitor'
END as intervention_urgency
FROM trend_analysis ta
)
SELECT
customer_id,
month,
total_health_score,
prev_month_score,
month_over_month_change,
three_month_trend,
trend_direction,
risk_category,
intervention_urgency,
retained_next_month,
-- Predictive probability based on historical patterns
CASE
WHEN total_health_score >= 90 THEN 0.95
WHEN total_health_score >= 80 THEN 0.85 + (month_over_month_change * 0.01)
WHEN total_health_score >= 70 THEN 0.75 + (month_over_month_change * 0.015)
WHEN total_health_score >= 60 THEN 0.65 + (month_over_month_change * 0.02)
WHEN total_health_score >= 50 THEN 0.50 + (month_over_month_change * 0.025)
WHEN total_health_score >= 40 THEN 0.35 + (month_over_month_change * 0.03)
ELSE 0.15 + GREATEST(-0.20, month_over_month_change * 0.035)
END as predicted_retention_probability
FROM risk_indicators
ORDER BY
CASE intervention_urgency
WHEN 'Immediate' THEN 1
WHEN 'This Week' THEN 2
WHEN 'This Month' THEN 3
ELSE 4
END,
total_health_score ASC;
Segmented Health Analysis
-- Analyze health scores by customer segments and characteristics
WITH customer_segments AS (
SELECT
customer_id,
subscription_tier,
customer_size,
industry,
acquisition_channel,
account_age_months,
CASE
WHEN account_age_months <= 3 THEN 'New'
WHEN account_age_months <= 12 THEN 'Growing'
WHEN account_age_months <= 24 THEN 'Mature'
ELSE 'Established'
END as customer_lifecycle_stage
FROM customers
),
segmented_health_analysis AS (
SELECT
cs.subscription_tier,
cs.customer_size,
cs.industry,
cs.customer_lifecycle_stage,
COUNT(*) as customer_count,
ROUND(AVG(chs.total_health_score), 1) as avg_health_score,
ROUND(PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY chs.total_health_score), 1) as median_health_score,
COUNT(CASE WHEN chs.total_health_score >= 90 THEN 1 END) as excellent_health_count,
COUNT(CASE WHEN chs.total_health_score >= 70 THEN 1 END) as healthy_count,
COUNT(CASE WHEN chs.total_health_score < 40 THEN 1 END) as critical_health_count,
ROUND(100.0 * COUNT(CASE WHEN chs.total_health_score >= 70 THEN 1 END) / COUNT(*), 1) as healthy_percentage,
ROUND(100.0 * COUNT(CASE WHEN chs.total_health_score < 40 THEN 1 END) / COUNT(*), 1) as at_risk_percentage
FROM customer_segments cs
JOIN customer_health_scores chs ON cs.customer_id = chs.customer_id
WHERE chs.month = DATE_TRUNC('month', CURRENT_DATE - INTERVAL '1 month') -- Last complete month
GROUP BY 1, 2, 3, 4
),
health_correlations AS (
SELECT
'Overall' as segment,
CORR(chs.total_health_score, cbm.monthly_revenue) as health_revenue_correlation,
CORR(chs.total_health_score, cum.features_used) as health_feature_correlation,
CORR(chs.total_health_score, csm.avg_csat) as health_satisfaction_correlation
FROM customer_health_scores chs
JOIN customer_billing_metrics cbm ON chs.customer_id = cbm.customer_id AND chs.month = cbm.month
JOIN customer_usage_metrics cum ON chs.customer_id = cum.customer_id AND chs.month = cum.month
JOIN customer_support_metrics csm ON chs.customer_id = csm.customer_id AND chs.month = csm.month
WHERE chs.month >= CURRENT_DATE - INTERVAL '3 months'
)
SELECT
subscription_tier,
customer_size,
customer_lifecycle_stage,
customer_count,
avg_health_score,
median_health_score,
healthy_percentage,
at_risk_percentage,
excellent_health_count,
critical_health_count,
RANK() OVER (ORDER BY avg_health_score DESC) as health_rank
FROM segmented_health_analysis
WHERE customer_count >= 10 -- Minimum segment size for statistical relevance
ORDER BY avg_health_score DESC;
Implementation Best Practices
Start with simple scoring models and iterate. Use historical data to validate score accuracy, weight components based on their correlation with retention, and regularly recalibrate the model.
Best Practices
1. Scoring Model Design
- Weight components based on correlation with retention
- Use both leading and lagging indicators
- Normalize scores across different customer segments
- Include both quantitative and qualitative factors
2. Data Quality
- Ensure complete and accurate data collection
- Handle missing data appropriately
- Regular data validation and cleansing
- Account for data freshness and timeliness
3. Actionable Insights
- Clear Thresholds: Define specific action triggers
- Trend Analysis: Monitor changes over time
- Risk Prioritization: Focus on highest-impact interventions
- Success Metrics: Track intervention effectiveness
4. Continuous Improvement
- Regularly validate model accuracy
- A/B test different scoring approaches
- Incorporate feedback from customer success teams
- Adapt to changing business and product dynamics
5. Integration Strategy
- Integrate with CRM and CS platforms
- Automate alerts and notifications
- Provide context and drill-down capabilities
- Enable self-service customer insights