Most "customer health score" implementations are a single number pulled from one data source, usually product usage, which misses the accounts that are heavy users but about to churn over a billing dispute, or light users who are perfectly happy and simply do not need to log in often. This workflow combines four independent signals into one composite score and, critically, routes three genuinely different outcomes rather than just flagging risk.
Workflow diagram
flowchart TD
A[Daily Trigger] --> B[Get Active Customers]
B --> C[Split In Batches]
C -->|done| Z[All Batches Complete]
C -->|batch| D[Pull Usage Data]
C -->|batch| E[Pull Support History]
C -->|batch| F[Pull Billing History]
C -->|batch| G[Pull NPS Score]
D --> H[Merge All Signals]
E --> H
F --> H
G --> H
H --> I[Calculate Usage Trend]
I --> J[Calculate Composite Score]
J --> K{Score Changed >15pts?}
K -->|No| L[Update Dashboard]
K -->|Yes| M{Health Tier}
M -->|At Risk| N[Trigger Playbook] --> O[Alert CSM] --> P[Create Save Task]
M -->|Expansion Signal| Q{Usage Growth >20%?}
Q -->|Yes| R[Notify Account Manager]
Q -->|No| S[No Action]
M -->|Watch| T[Add To Watch List] --> U[Schedule Check-In]
P --> V[Merge Outcomes]
R --> V
S --> V
U --> V
V --> L
L --> W[Log Score History]
W --> C Every branch shown here (IF/Switch outcomes) exists as a real conditional in the downloadable JSON, not a simplification for this diagram.
Why a single signal produces false positives and false negatives
Product usage alone flags any account with declining logins as at-risk, including perfectly satisfied customers who simply configured the product once and now let it run unattended, exactly the outcome many B2B tools are designed to produce. Support ticket volume alone flags engaged customers who ask a lot of questions as risky, when frequent contact is often a sign of investment, not dissatisfaction.
The workflow pulls all four signals in parallel, usage trend, support ticket sentiment and volume, billing and payment health, and the latest NPS response, and combines them in Calculate Composite Health Score with configurable weights. The specific weighting in the template (40% usage, 25% support, 20% billing, 15% NPS) is a starting point, not a law, tuned by looking at which signal actually preceded real churn events historically.
Batch processing and why it protects your other integrations
Split In Batches processes customers 25 at a time rather than all at once. At meaningful scale, calling four different rate-limited APIs for every customer in one burst is the single most common way a health-scoring workflow gets throttled or banned outright by one of its own data sources.
The batching loop (Loop Next Batch feeding back into Split In Batches) also means a single customer's API failure does not halt scoring for the rest of the portfolio, each batch completes independently.
Three-way routing: risk, stability, and expansion
The Health Tier switch does not just separate healthy from at-risk. A score climbing alongside strong usage growth routes to Identify Expansion Opportunity, flagging the account for an upsell conversation rather than treating growth as a non-event. This is the detail most churn-prediction builds miss entirely: the same infrastructure that catches risk early should also catch opportunity early, using the same data.
Score Changed Significantly? gates action on movement greater than 15 points, not on the absolute score. Without this gate, a stable customer sitting at a permanently low-but-fine score of 45 would re-trigger the at-risk playbook every single day, training your CS team to ignore the alerts entirely.
Node-by-node reference
| Node | Type | Role |
|---|---|---|
| Split In Batches | Split In Batches | Processes 25 accounts at a time to protect rate limits |
| Pull Usage / Support / Billing / NPS | HTTP Request ×4 | Four independent signal sources per customer |
| Calculate Composite Health Score | Code | Weighted 0-100 score across all four signals |
| Score Changed Significantly? | IF | Gates action on movement, not absolute score, prevents alert fatigue |
| Health Tier | Switch | Three-way split: at-risk, watch, healthy/expansion |
| Identify Expansion Opportunity | IF | Catches growth signals, not just risk signals |
| Log Score History | HTTP Request | Historical record used to re-validate the scoring weights over time |
27 total nodes in the downloadable file, including sticky-note documentation embedded directly on the canvas.
Key logic, in code
Composite health score calculation
const usageScore = $json.usageTrendScore; // 0-100
const supportScore = $json.supportSentimentScore;
const billingScore = $json.billingHealthScore;
const npsScore = $json.npsNormalizedScore;
const WEIGHTS = { usage: 0.40, support: 0.25, billing: 0.20, nps: 0.15 };
const composite =
usageScore * WEIGHTS.usage +
supportScore * WEIGHTS.support +
billingScore * WEIGHTS.billing +
npsScore * WEIGHTS.nps;
return [{
json: {
...$json,
score: Math.round(composite),
scoreDelta: Math.round(composite) - $json.previousScore,
}
}]; Before / after
| Metric | Before | After this workflow |
|---|---|---|
| Churn signals caught before renewal | Often discovered at cancellation | Flagged weeks earlier via composite score |
| False-positive risk alerts | High, single-signal (usage only) | Reduced, requires agreement across signals |
| Expansion opportunities identified | Ad hoc, rep-dependent | Systematically flagged alongside risk |
| CS team alert fatigue | Common with daily scoring | Mitigated by the 15-point movement gate |
Prerequisites
- n8n v1.40+ with Split In Batches v3
- CRM API access (HubSpot or equivalent) for the account list and task creation
- Product analytics API (Mixpanel, Amplitude or similar)
- Zendesk or equivalent support platform API
- Stripe billing data access, an NPS tool API (Delighted or equivalent)
Common pitfalls
Do not deploy the default weights unchanged
The 40/25/20/15 split is a reasonable starting point, not a validated model for your business. Revisit it against real churn outcomes after your first quarter of data.
Batch size needs tuning to your API limits
25 is conservative. Check each connected API's actual rate limit and adjust Split In Batches accordingly, too large a batch reintroduces the throttling problem this pattern exists to prevent.
A score is a conversation starter, not a verdict
An automated save task or alert should trigger a human conversation, not an automated retention email. Customers can tell the difference, and it usually backfires.
Want this deployed, configured and monitored?
The template is free. Wiring in your real credentials, tuning the logic to your business, and keeping it running when an upstream API changes is what we do.
Get my free automation plan →Frequently asked questions
How much historical data do I need before this is reliable?
Enough churn events to validate the weighting, typically a full quarter at minimum, longer for lower-churn businesses. Run it and log scores well before trusting the at-risk playbook automatically.
Can this work for a PLG product with no assigned CSM?
Yes, route the at-risk alert to a shared Slack channel or trigger an automated in-app or email intervention instead of a named CSM task.
What if we do not have an NPS program?
Drop the NPS input and redistribute its 15% weight across the remaining three signals, the model degrades gracefully with three signals instead of four.