AI-based Customer Health Score
Customer Health Score (CHS) is a comprehensive indicator of how engaged a customer is with a product and the likelihood of renewal or churn. For B2B SaaS and subscription services, it is a leading indicator of NRR (Net Revenue Retention). The ML approach allows for the transition from CSM intuition to an objective, repeatable assessment.
Signals for the model
Product Usage:
- DAU/WAU/MAU: activity of the main users of the account
- Feature adoption: percentage of key features adopted in the last 30 days
- Depth of use: advanced features vs. basic ones
- Stagnation: Decline in usage over the past 4 weeks
Support & Success signals:
- Open tickets without a response > 3 days - negative signal
- NPS, CSAT scores for the last 6 months
- The EBR (Executive Business Review) took place – a positive signal
- Escalations: management-level complaints
Commercial indicators:
- Renewal date proximity: < 90 дней → повышенное внимание
- Expansion or contraction in the last 12 months
- Invoice payment delays: late payments
- Contract modifications: attempts to revise the terms
Relationship signal:
- Sponsor changes: the champion left the account - high risk
- Multi-threading: how many contacts the CSM knows (< 2 = single-threaded)
- Last meaningful interaction: when was the last time there was a real conversation
Feature Engineering
def compute_customer_health_features(account_id, lookback_days=90):
usage = get_product_usage(account_id, lookback_days)
support = get_support_tickets(account_id, lookback_days)
commercial = get_crm_data(account_id)
return {
# Usage trends
'usage_trend_slope': np.polyfit(range(lookback_days), usage['daily_active_users'], 1)[0],
'feature_adoption_score': len(usage['active_features']) / total_key_features,
'power_user_ratio': usage['high_frequency_users'] / usage['total_seats'],
# Support health
'open_critical_tickets': support[support['priority'] == 'critical']['count'],
'avg_resolution_time_days': support['avg_resolution_time'],
'recent_nps': support['last_nps_score'],
# Commercial
'days_to_renewal': (commercial['renewal_date'] - today).days,
'logo_expansion_12m': commercial['arr_change_12m'],
'payment_delay_days': commercial['avg_payment_delay'],
# Relationship
'sponsor_change_6m': commercial['sponsor_changed_flag'],
'contacts_known': commercial['known_contacts_count'],
'days_since_last_call': (today - commercial['last_substantive_contact']).days
}
Models and architecture
Composite Score (correct baseline):
def rule_based_health_score(features):
score = 100 # start at 100
# Usage penalties
if features['usage_trend_slope'] < -0.1:
score -= 20
if features['feature_adoption_score'] < 0.3:
score -= 15
# Support penalties
if features['open_critical_tickets'] > 0:
score -= 25
if features['recent_nps'] and features['recent_nps'] < 7:
score -= 15
# Commercial risk
if features['days_to_renewal'] < 60 and features['logo_expansion_12m'] < 0:
score -= 20
return max(0, min(100, score))
ML model floor: LightGBM or Logistic Regression trained on historical "renewed/departed" data after 12 months. Advantage vs. rule: identifies nonlinear interactions (for example, a decrease in usage alone is not a risk, but when combined with an upcoming renewal, it is critical).
Temporal validation:
# Walk-forward: we train on cohorts < 12 months ago, we predict on later ones
# Metric: AUC of 90-day churn prediction
# Baseline: just the renewal date + the latest NPS
Risk segmentation and actions
Risk Tiers:
| Level | Score | Action |
|---|---|---|
| Healthy | 70-100 | Quarterly check-in, expansion play |
| Attention | 50-69 | Monthly CSM review, fix pain points |
| At Risk | 30-49 | EBR scheduling, exec involvement |
| Critical | 0-29 | Save playbook, potential concessions |
Automated Playbooks:
def trigger_playbook(account, health_score, reason_codes):
if health_score < 30:
crm.create_task(owner='csm_manager', type='urgent_review', account=account)
slack.notify('#csm-alerts', f"CRITICAL: {account.name} score={health_score}")
elif health_score < 50 and 'usage_decline' in reason_codes:
gainsight.enroll_in_playbook(account, 'activation_campaign')
elif health_score > 80 and account.days_to_renewal < 90:
crm.create_opportunity(account, type='expansion', amount=account.arr * 0.2)
Integration with CS tools
Gainsight, ChurnZero, Totango: These platforms already have native health scoring. A custom ML model exports the score via an API → replaces or supplements the built-in rules.
CRM (Salesforce, HubSpot): Custom field "AI Health Score" on the Account object. Updated weekly. Used in reports and forecasting.
Product Analytics (Amplitude, Mixpanel, Heap): Usage data source. Separate API/export for B2B account-level aggregation.
Timeframe: Feature pipeline + rule-based scoring + Salesforce integration — 3-4 weeks. ML model training and validation + automated playbook triggers + Gainsight integration — 6-8 weeks.







