Default components
Every built-in Product Health signal — what it measures, how to read it, and what to do when it moves.
New projects start from the Product Health template: 23 components, each isolating a distinct churn signal so a single bad number can't hide behind everything else. They are grouped into seven themes below. Expand any component for a full breakdown — how we collect it, how to read it, how to analyze it, and what to do when it turns soft.
Each component computes a raw value, then maps it to a 0–100 score. At its
good threshold (or above) it scores 100; at its
warn threshold (or worse) it scores 30; in between
it is linear. Higher is better signals rise with the value;
inverse (lower is better) signals fall as the value rises. The
account's overall health is the weight-proportional average of
every enabled component, banded as Healthy ≥ 80 · Watch ≥ 60 · Risky ≥ 40 ·
Cold < 40. Weights are relative, so you can retune one without renormalizing
the rest.
Product usage
The core "are they getting value?" signals — and the largest share of the score. Breadth (feature depth, seats) and rhythm (logins, stickiness, sessions) are the earliest evidence an account is embedding the product into real work. Read them together: strong breadth with weak rhythm — or the reverse — is more telling than any single tile.
Evidence: depth and frequency of product use are consistently the strongest leading indicators of renewal in customer-success research (Gainsight, Customer Success benchmarks). Retention itself compounds: Reichheld & Sasser's classic loyalty-economics work (Bain / HBR) found a 5% lift in retention can raise profit 25–95%.
Login frequency (7 / 14 / 30d)loginHow often the account logs in, weighting the most recent week the most.
Higher is bettergood 12warn 4weight 10
loginHow often the account logs in, weighting the most recent week the most.
- How we collect it
- From app.login (direct API) → metric login. The 7-, 14-, and 30-day counts are blended 0.5 / 0.3 / 0.2, so this week carries the most weight.
- How to read it
- The raw value is a blended login count: (7-day ×0.5) + (14-day ×0.3) + (30-day ×0.2). A blended value of ≥12 scores 100 (Healthy); ≤4 scores 30 (Cold); around 8 lands mid-band (Watch/Risky). Because the current week is weighted heaviest, a quiet recent week pulls the score down even when the 30-day total still looks large.
- How to analyze it
- Frequency, not raw volume, is the clearest engagement signal — accounts that log in on a steady rhythm renew far more often than ones with occasional bursts. A falling blended count while monthly totals still look fine means recent weeks are quietly thinning out.
- What to do
- On a sustained drop, confirm whether it is seasonal or real disengagement, then trigger a check-in or re-onboarding nudge before the account goes silent.
- Tune it
- Weight 10 is the largest in the template — keep it high if logins are your truest engagement proxy, but lower it for products driven by APIs or integrations where humans rarely log in. Raise good above 12 if your healthy accounts log in more often, or raise warn to flag drift earlier. Weight, thresholds, and the metric spec are all editable in Settings → Components.
DAU / WAU style ratiologinStickiness — how active the last 7 days were versus the 30-day pace.
Higher is bettergood 45warn 15weight 8
loginStickiness — how active the last 7 days were versus the 30-day pace.
- How we collect it
- Distinct active days from login events in the last 7 vs last 30, expressed as a 0–100 ratio.
- How to read it
- Raw value = (active days in last 7 ÷ 7) ÷ (active days in last 30 ÷ 30) × 100, capped at 100. ≥45 → 100, ≤15 → 30, mid-30s sits in Watch. A value near 100 means this week matched or beat the monthly pace; a value well below it means the account was busier earlier in the month than it is now.
- How to analyze it
- A habit/stickiness proxy. Roughly 20%+ DAU/WAU is a common healthy SaaS benchmark; a high ratio means the product is part of the daily routine — the hardest thing for a competitor to displace.
- What to do
- Low stickiness alongside healthy totals points to power-user concentration; broaden adoption across the wider team.
- Tune it
- Lower the weight if your product is intentionally low-frequency (monthly reporting, quarterly reviews) where daily stickiness isn't the goal. Raise good/warn if your category's healthy stickiness runs higher than the ~20% baseline. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Feature depthfeature_usedShare of your feature catalog the account actually touches.
Higher is bettergood 55warn 20weight 8
feature_usedShare of your feature catalog the account actually touches.
- How we collect it
- Distinct feature names (payload feature / label / name) from app.feature.used and the SDK feature_used event, over a default catalog of 10 features.
- How to read it
- Raw value is the percentage of your catalog used: distinct features ÷ catalog size × 100. With the default catalog of 10, touching ~6 features → ~55% → 100; touching 2 → ~20% → 30. The score scales directly with catalog size, so an inaccurate catalog count distorts every account's reading.
- How to analyze it
- Breadth of adoption is a proxy for switching cost — accounts that lean on many features are far stickier than single-feature users. Shallow depth flags accounts that bought more than they use, the classic shape that downsizes at renewal.
- What to do
- Narrow depth → targeted education on high-value modules the account has never opened.
- Tune it
- The default catalog is 10 features — if you ship far more or fewer, edit the spec's totalFeatures so the ratio reflects reality, otherwise every score is mis-scaled. Lower the weight for products where most value comes from one or two core features. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Session lengthsession.session_minutesAverage minutes per session.
Higher is bettergood 15warn 3weight 6
session.session_minutesAverage minutes per session.
- How we collect it
- Average of payload session_minutes from app.session.end / SDK session_ended over the last 30 days.
- How to read it
- Raw value is the mean session length in minutes over 30 days. ≥15 min → 100, ≤3 min → 30, ~9 min lands mid-band. Read it with frequency, not alone: short-but-frequent can be perfectly healthy, while a very high average can signal users getting stuck rather than getting value.
- How to analyze it
- A depth-of-engagement proxy that must be read with frequency: short but frequent can be perfectly healthy (quick habitual checks), while short and infrequent signals disengagement. Unusually long sessions are not automatically good — they can mean confusion, so cross-check frustration signals.
- What to do
- Interpret alongside feature depth and frustration before acting; the number alone is ambiguous.
- Tune it
- Lower the weight or widen thresholds if your product is built for short, frequent visits (dashboards, status checks) where long sessions aren't expected. Raise good for tools meant for deep, sustained work. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Seats used vs purchasedseat_used / seat_purchasedLicense utilization — active seats over purchased seats.
Higher is bettergood 75warn 40weight 6
seat_used / seat_purchasedLicense utilization — active seats over purchased seats.
- How we collect it
- Latest payload count on billing.seats.used vs billing.seats.purchased (commonly fed by a billing integration).
- How to read it
- Raw value is used ÷ purchased × 100, clamped 0–100, from the most recent seat payloads. ≥75% → 100, ≤40% → 30. If no purchased-seat figure has ever arrived the component skips (no score) rather than reading 0, so it never punishes accounts you haven't instrumented.
- How to analyze it
- Utilization is a direct renewal-risk signal — low seat usage is the single most common justification a buyer uses to downsize or cancel. High, sustained utilization is also your clearest expansion opening.
- What to do
- <40% → drive activation of unused seats well ahead of renewal; >90% sustained → open an expansion conversation.
- Tune it
- Raise the weight for seat-based pricing where utilization directly drives renewal and expansion; lower or disable it for usage- or consumption-based pricing where seats are irrelevant. Tighten warn toward 50–60 if you want earlier alerts on under-adoption. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Engagement & activity
Recency, reach, and a strong start. These catch who is active and how recently — the dimensions that move first when an account begins to drift. A healthy account is recent, multi-user, and well-onboarded; a gap in any one of the three is an early crack.
Evidence: recency is a core RFM churn predictor, and early activation / time-to-value strongly predicts long-term retention (Amplitude & Reforge product benchmarks). Single-threaded, single-user accounts are structurally more churn-prone than multi-user ones.
Days since last loginloginHow long since the account last logged in.
Lower is bettergood 7warn 21weight 8
loginHow long since the account last logged in.
- How we collect it
- Days between now and the most recent login event.
- How to read it
- Raw value is the number of days since the last login (inverse — lower is better). ≤7 days → 100, ≥21 days → 30, ~14 days sits mid-band. The score decays linearly through the gap, so it gives early warning rather than flipping only once the account is long gone.
- How to analyze it
- Recency is one of the oldest and most reliable churn predictors — the 'R' in RFM analysis. A login gap widening past the account's normal cadence is often the first visible step toward cancellation.
- What to do
- Crossing the warn line should trigger a re-engagement touch before the gap normalizes into churn.
- Tune it
- Tighten good/warn (e.g., 3/10) for daily-use products so gaps flag faster; loosen them for weekly or monthly tools so a normal cadence isn't penalized. Keep the weight high — recency is among the most reliable churn predictors. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Active users (30d)active_userHow many distinct people used the account this month.
Higher is bettergood 4warn 1weight 7
active_userHow many distinct people used the account this month.
- How we collect it
- Distinct external_user_id in app.user.active (and SDK page_viewed) over the last 30 days.
- How to read it
- Raw value is the count of distinct users seen in 30 days. ≥4 → 100, ≤1 → 30, with 2–3 in between. Read it against the account's seat count: 3 active users is healthy for a 4-seat plan but a warning sign for a 50-seat rollout.
- How to analyze it
- Multi-user accounts are dramatically stickier — single-threaded accounts churn the moment their one champion leaves. Breadth of active users is a structural retention moat, not just an engagement number.
- What to do
- One active user on a multi-seat plan is champion risk; broaden the footprint and identify a backup sponsor.
- Tune it
- Raise good/warn to match your typical account size — '4 users' is healthy for an SMB but low for an enterprise rollout. Increase the weight if multi-user adoption is central to your stickiness story. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Onboarding in first weekonboarding_completedDid the account complete onboarding within 7 days of signup?
Pass / failweight 7
onboarding_completedDid the account complete onboarding within 7 days of signup?
- How we collect it
- Whether an onboarding_completed event fell within 7 days of account creation. Binary: yes → 100, no → 30.
- How to read it
- There is no sliding scale — it is pass (100) or fail (30). The window is fixed at the first 7 days after account creation, so it is effectively frozen once an account is older than a week. That permanence is why it carries a heavy weight despite being binary.
- How to analyze it
- Time-to-value is among the strongest predictors of long-term retention — accounts that reach their first 'aha' quickly retain far better than slow starters, and a weak first week predicts churn months ahead.
- What to do
- A miss is a durable risk flag — prioritize hands-on onboarding recovery rather than waiting for usage to decline.
- Tune it
- Being binary, there are no thresholds to tune — only the weight. Keep it high (or raise it) for products with a meaningful setup phase; lower it if first value is instant and onboarding isn't a distinct step. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Support health
Support load and tone are leading indicators of frustration — they often move weeks before an account says anything. Volume, speed, and tone tell different stories: a quiet queue with a single negative tag can matter more than a busy one that resolves quickly.
Evidence: Dixon, Toman & DeLisi, "Stop Trying to Delight Your Customers" (Harvard Business Review, 2010) showed that reducing customer effort, not exceeding expectations, is what protects loyalty — high-effort support experiences are a powerful predictor of disloyalty.
Open ticket pressureopened − resolvedRoughly how many support tickets are open right now.
Lower is bettergood 1warn 3weight 6
opened − resolvedRoughly how many support tickets are open right now.
- How we collect it
- support_ticket_opened minus support_ticket_resolved over 30 days. Sources: direct API, or Intercom / Zendesk / Freshdesk via your event mappings (Intercom ticket topics are pre-mapped).
- How to read it
- Raw value is opened minus resolved in the window, floored at 0 (inverse). ≤1 open → 100, ≥3 → 30. Note the failure mode: if no support events arrive at all it reads 0 and looks perfectly healthy — a clean score here only means something once tickets are flowing in.
- How to analyze it
- Standing unresolved load is friction the customer is actively living with. A backlog that grows faster than it clears is the shape that precedes escalations and quiet non-renewals.
- What to do
- Persistent pressure → assign a clear owner, work the backlog down, and follow up personally.
- Tune it
- Lower the weight or disable it if no support integration feeds ticket events, otherwise it reads artificially healthy for the wrong reason. Tighten warn for high-touch segments where even a couple of open tickets matter. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Ticket sentiment (negative)support_ticket_negativeCount of negatively-tagged support interactions.
Lower is bettergood 0warn 2weight 5
support_ticket_negativeCount of negatively-tagged support interactions.
- How we collect it
- Count of support.ticket.negative events over the last 30 days.
- How to read it
- Raw value is the count of negative-tagged events in 30 days (inverse). 0 → 100, ≥2 → 30, so a single negative interaction already pulls the score into Watch. It relies on your source tagging sentiment — without that signal it simply reads 0.
- How to analyze it
- Tone is a leading indicator that precedes the formal complaint and the silent non-renewal. Even one or two negative interactions on a high-value account are worth attention.
- What to do
- Any negative tag on a strategic account → personal outreach from an owner, not a queue reply.
- Tune it
- Raise the weight for high-value or strategic accounts where tone matters more than volume. Set warn to 1 if you want a single negative interaction to register rather than waiting for a pattern. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Ticket velocity spikesupport_ticket_openedA sudden jump in new tickets versus the prior week.
Lower is bettergood 0warn 3weight 5
support_ticket_openedA sudden jump in new tickets versus the prior week.
- How we collect it
- This week's opened tickets minus last week's (same window size).
- How to read it
- Raw value is this week's opened tickets minus last week's, floored at 0 (inverse) — it measures change, not level. 0 (flat or down) → 100, +3 or more → 30. A steady high volume scores well here; only an acceleration is penalized.
- How to analyze it
- A spike often signals a release regression, a confusing change, or a newly-onboarded team hitting walls. Watching the rate of change surfaces problems before absolute counts look bad.
- What to do
- Investigate the spike's root cause — release, feature, or new team — rather than just clearing tickets.
- Tune it
- Lower the weight if your ticket volume is naturally spiky (scheduled launches, seasonal peaks) to avoid false alarms. Raise warn if small fluctuations are normal and only a real surge should count. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Time to resolutionresolution_hoursAverage hours to resolve a ticket.
Lower is bettergood 8warn 48weight 4
resolution_hoursAverage hours to resolve a ticket.
- How we collect it
- Average payload resolution_hours on resolved tickets over the last 30 days.
- How to read it
- Raw value is the mean resolution_hours across resolved tickets in 30 days (inverse). ≤8h → 100, ≥48h → 30, ~28h sits mid-band. It only reflects tickets that carry a resolution_hours payload, so accounts with no resolved tickets contribute nothing here.
- How to analyze it
- Resolution speed is the most tangible form of customer effort, and effort — not delight — is what protects loyalty. Slow resolutions compound: the longer a problem stays open, the more it colors the renewal decision.
- What to do
- Sustained slow resolution → review staffing and process for that account's tier.
- Tune it
- Align good/warn with your published SLA so the score reflects your actual promise, not a generic default. Raise the weight for premium tiers where speed is part of what the customer pays for. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Relationship & lifecycle
Context that tunes urgency and cost-of-churn rather than raw engagement. A renewal next week is more urgent than one next year; a high-MRR account at risk deserves attention first. Use these to decide who to act on first when several accounts look equally soft — not to judge health on their own.
Evidence: Reichheld, "The One Number You Need to Grow" (Harvard Business Review, 2003) established stated satisfaction (NPS) as a loyalty proxy — useful, but lagging and self-selected, so it confirms rather than leads. Churn risk is front-loaded into a customer's first 30–90 days.
Days until renewalaccount.RenewalAtTime left until the contract renews.
Higher is bettergood 90warn 30weight 4
account.RenewalAtTime left until the contract renews.
- How we collect it
- Derived from the account's RenewalAt date — no events needed.
- How to read it
- Raw value is days remaining until renewal (higher = more runway). ≥90 days → 100, ≤30 days → 30. The score falls as the date approaches — by design, so a soft account becomes more urgent the closer renewal gets. Accounts with no RenewalAt set are skipped.
- How to analyze it
- This is an urgency multiplier, not a health signal — a mediocre score two weeks from renewal is far more dangerous than the same score a year out. It tells you when to act.
- What to do
- As renewal nears, prioritize accounts whose other signals are soft; the runway is shrinking.
- Tune it
- Raise good/warn (e.g., 120/60) if your sales motion needs a longer runway to act on at-risk renewals. Keep the weight modest — it should nudge prioritization, not dominate the health score. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Contract value (MRR tier)account.MrrRevenue-at-risk band from the account's MRR.
Higher is betterweight 3
account.MrrRevenue-at-risk band from the account's MRR.
- How we collect it
- Banded from account Mrr: ≥$5k → 85, ≥$1k → 75, >$0 → 65, otherwise 55.
- How to read it
- Not a sliding scale — it snaps to one of four bands by MRR (85 / 75 / 65 / 55). Even a zero-MRR account never scores below 55, so this component lifts the floor for paying accounts rather than penalizing anyone. It encodes how much a churn would cost, not how likely it is.
- How to analyze it
- Not a churn-likelihood signal — a prioritization lens. Two equally at-risk accounts are not equal if one is 10× the revenue; concentrate scarce attention where the dollar impact is largest.
- What to do
- Use to triage: same risk, higher MRR → handle first.
- Tune it
- The bands ($5k / $1k) are fixed in the spec — edit them to match your own revenue distribution so 'high value' means high value for your business. Keep the weight low: it's a triage lens, not a churn signal, and over-weighting it makes big accounts look healthy regardless of behavior. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Customer tenureaccount.CreatedAtHow long the account has been a customer.
Higher is bettergood 365warn 30weight 3
account.CreatedAtHow long the account has been a customer.
- How we collect it
- Days since account creation — no events needed.
- How to read it
- Raw value is days since the account was created (higher = more established). ≥365 days → 100, ≤30 days → 30. New accounts deliberately start low here, reflecting that early-life churn risk is highest; the score climbs steadily as trust is earned.
- How to analyze it
- Churn risk is front-loaded — the first 30–90 days carry the highest cancellation rate, and tenure earns trust. A young account behaves nothing like a two-year one, so this contextualizes every other signal.
- What to do
- Treat new-account dips as fragile and lean in early; treat long-tenured dips as notable departures from a known baseline.
- Tune it
- Lower good (e.g., to 90–180 days) if your customers reach a stable, trusting relationship quickly. Keep the weight small — tenure is context for the other signals, not a health verdict on its own. Weight, thresholds, and the metric spec are all editable in Settings → Components.
NPS / CSAT (optional)nps_response / csat_responseBlended survey satisfaction, when you collect it.
Higher is betterweight 2
nps_response / csat_responseBlended survey satisfaction, when you collect it.
- How we collect it
- Average payload score from survey.nps (×10) and survey.csat (×20), blended 60/40 over 180 days. Skipped entirely if you send neither.
- How to read it
- Raw value is a 0–100 blend: NPS×10 and CSAT×20 are each clamped to 100, then mixed 60/40 (or whichever you collect). It is already on the score's scale, so it maps almost directly. Crucially it auto-skips when no survey events exist, so it never drags down accounts you haven't surveyed.
- How to analyze it
- Stated sentiment complements behavior, but it lags and is self-selected (detractors and fans answer most). Trust it as confirmation, not a primary alarm — behavior usually moves first.
- What to do
- A detractor score on an otherwise-healthy account is an early warning worth a direct conversation.
- Tune it
- Because it auto-skips with no surveys, you can leave it enabled at a low weight with no downside. Raise the weight only if you survey consistently and trust your response rate; otherwise let behavioral signals lead. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Behavioral & UX friction
Friction the customer feels but rarely reports — captured automatically by the browser SDK with no extra instrumentation. Because they're auto-captured, a flat zero can simply mean the SDK isn't installed; confirm coverage before trusting a clean score here.
Evidence: UX research (Nielsen Norman Group) treats rage clicks, dead clicks, and form abandonment as markers of unmet intent; repeated friction erodes satisfaction and completion, and correlates with disengagement.
Frustration signals (30d)frustration_scoreRage clicks and abandoned forms from auto-capture.
Lower is bettergood 0warn 8weight 6
frustration_scoreRage clicks and abandoned forms from auto-capture.
- How we collect it
- Count of SDK rage_click + form_abandoned events (→ frustration_score) over 30 days. No extra instrumentation beyond the browser SDK.
- How to read it
- Raw value is the count of frustration events in 30 days (inverse). 0 → 100, ≥8 → 30, ~4 sits mid-band. It depends on the browser SDK being installed; server-only integrations won't generate it, in which case it reads 0 by absence rather than by good UX.
- How to analyze it
- Unsolicited friction — users rarely file a ticket about a frustrating form, they just struggle or leave. Rage clicks cluster on broken or confusing UI; abandonment marks intent that never completed.
- What to do
- Recurring frustration on the same screen is a product/UX fix, not a CS touch — route it to the team that owns that surface.
- Tune it
- Raise warn if your auto-capture is noisy (some UIs trigger benign rage clicks) to cut false positives. Increase the weight for self-serve products where unreported friction is your main early-warning channel. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Client errors (30d)error_rateJavaScript errors the account's users hit.
Lower is bettergood 0warn 5weight 4
error_rateJavaScript errors the account's users hit.
- How we collect it
- Count of SDK js_error events (→ error_rate) over the last 30 days.
- How to read it
- Raw value is the count of captured JS errors in 30 days (inverse). 0 → 100, ≥5 → 30. The threshold is strict — set it against your real baseline, because a busy app may emit a few benign errors that don't reflect a degraded experience.
- How to analyze it
- Errors are objective friction — a user hitting repeated failures is being actively blocked from value. Even when they never complain, error exposure correlates with disengagement.
- What to do
- Cross-reference errored sessions with the account and escalate reproducible failures to engineering quickly.
- Tune it
- Set warn relative to your normal error baseline — 0/5 may be too strict for a large app. Lower the weight if you already monitor errors in a dedicated tool and don't want to double-count. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Intelligence & trend
Trends across all signals at once — they catch decline even when every individual number still looks fine from the last active period. When these turn red while the rest stay green, trust the trend: it is usually seeing the change before the levels catch up.
Evidence: in customer-success practice, gradual disengagement — not a single event — precedes most cancellations, which is why usage-decline and silence are the canonical early-warning signals (Gainsight early-warning frameworks).
Account silenceall eventsDays since any event of any kind for the account.
Lower is bettergood 7warn 21weight 5
all eventsDays since any event of any kind for the account.
- How we collect it
- Days since the most recent event across every metric. Skipped if the account has no events at all.
- How to read it
- Raw value is days since the most recent event of any type (inverse). ≤7 days → 100, ≥21 → 30. Unlike days-since-last-login it watches every signal at once, so it only goes quiet when the account truly goes dark — which makes a low score here especially meaningful.
- How to analyze it
- The broadest recency net — it catches accounts that went quiet across the board, even if the last active snapshot looked healthy. Silence frequently precedes a cancellation by weeks.
- What to do
- Lengthening silence is a high-priority re-engagement trigger; do not wait for renewal.
- Tune it
- Tighten good/warn for high-frequency products where three weeks of total silence is already very late. Keep the weight meaningful — it's the broadest safety net and catches accounts the per-metric signals miss. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Activity drop (WoW)all eventsHow much total activity fell this week versus last.
Lower is bettergood 20warn 60weight 5
all eventsHow much total activity fell this week versus last.
- How we collect it
- 100 − (this week's events ÷ last week's × 100), across all events. Skipped with no prior-week baseline.
- How to read it
- Raw value is the percentage drop week-over-week: 0 means flat or growing, 100 means total silence versus last week. ≤20% drop → 100, ≥60% → 30. It needs a prior-week baseline, so brand-new accounts skip it until there is something to compare against.
- How to analyze it
- Catches the rate of disengagement, not the absolute level — a steep week-over-week fall is an early tremor even when totals still look respectable. The trend leads the level.
- What to do
- A sharp drop is worth a quick look while it is fresh — find what changed (champion left, season, competitor).
- Tune it
- Loosen warn if week-over-week swings are normal for your usage pattern, so only real cliffs score low. Raise the weight if catching momentum changes early matters more to you than absolute activity levels. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Growth & advocacy
The positive signals — an account deepening, not just surviving. Expansion and referrals are the leading edge of net revenue retention. These only ever lift a score, never sink it, so treat them as upside flags for expansion plays rather than risk alerts.
Evidence: net revenue retention is one of the strongest drivers of SaaS value (Bessemer / SaaS benchmarks), and active referral is a stronger proof of advocacy than any stated score, because the customer stakes their own reputation on it.
Seat expansionseat_expandedDid the account add seats recently?
Higher is bettergood 1warn 0weight 3
seat_expandedDid the account add seats recently?
- How we collect it
- Count of billing.seat.expanded events (often via a billing integration) over the last 30 days.
- How to read it
- Effectively a yes/no with a soft floor: ≥1 expansion event in 30 days → 100, 0 → 30. It is a bonus signal — it lifts healthy, growing accounts rather than punishing steady ones, since 'no expansion this month' is normal for most.
- How to analyze it
- Expansion is the strongest positive health signal — accounts add seats when they are getting value and rolling out wider. It is also the leading edge of net revenue retention.
- What to do
- Expanding accounts are advocacy and case-study candidates; nurture them, do not just renew them.
- Tune it
- Raise the weight if expansion is central to your growth model and you want healthy accounts rewarded for it. Lengthening the window in the spec captures slower expansion cycles. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Plan upgradesplan_upgradedDid the account move to a higher plan?
Higher is bettergood 1warn 0weight 3
plan_upgradedDid the account move to a higher plan?
- How we collect it
- Count of billing.plan.upgraded events over the last 180 days.
- How to read it
- Yes/no with a soft floor over a long 180-day window: ≥1 upgrade → 100, 0 → 30. The wide window means a single upgrade keeps lifting the score for months, reflecting that a recent upgrade is a durable signal of commitment.
- How to analyze it
- A willingness-to-pay-more signal — upgrades reflect realized value and rising commitment, and they meaningfully lower near-term churn risk.
- What to do
- Recent upgraders are prime expansion and reference targets; reinforce the value that drove the upgrade.
- Tune it
- Widen or narrow the 180-day window to match your typical upgrade cadence. Raise the weight if upgrades are a strong loyalty signal in your data; keep it modest if upgrades are rare across your base. Weight, thresholds, and the metric spec are all editable in Settings → Components.
ReferralsreferralDid the account refer someone?
Higher is bettergood 1warn 0weight 2
referralDid the account refer someone?
- How we collect it
- Count of growth.referral events over the last 180 days.
- How to read it
- Yes/no with a soft floor over 180 days: ≥1 referral → 100, 0 → 30. It carries the lowest weight in the template on purpose — referrals are sparse, so it should reward advocates without dragging down the majority who simply haven't referred.
- How to analyze it
- Referring is the clearest behavioral proof of advocacy — stronger than any stated survey score, because the customer is staking their own reputation. Referrers are among your stickiest accounts.
- What to do
- Thank and activate referrers; they are your best growth and renewal anchors.
- Tune it
- Keep the weight low by default — referrals are sparse, so a high weight would make most accounts look worse simply for not referring. Lengthen the window if your referral cycle is long. Weight, thresholds, and the metric spec are all editable in Settings → Components.
Make them your own
Every threshold, weight, and metric spec above is editable in Settings → Components. Lower a weight you don't trust, disable a signal you don't collect, or build a brand-new component from the metric source picker. The score and every widget update together.