KiteDocs
Guides

Health score

Design, compute, calibrate, and explain a customer health score.

A health score is a current, explainable summary, not a churn probability. Start with a small number of independent product signals that a CS team can act on. Keep commercial facts such as renewal date outside the score unless they truly describe health.

health/overall.ts
export default defineHealth({
  id: 'overall',
  name: 'Overall health',
  components: {
    adoption: {
      name: 'Feature adoption',
      weight: 0.4,
      compute: {
        type: 'feature_adoption',
        features: ['exports', 'dashboards', 'alerts'],
        period: '30d',
        respectPlanFeatures: true,
      },
    },
    engagement: {
      name: 'Engagement',
      weight: 0.4,
      compute: {
        type: 'event_frequency',
        event: 'feature.used',
        period: '30d',
        target: 20,
        minScore: 5,
      },
    },
    stability: {
      name: 'Stability',
      weight: 0.2,
      compute: {
        type: 'inverse_event_count',
        event: 'api.error',
        period: '30d',
        penaltyPerEvent: 5,
        maxScore: 100,
      },
    },
  },
  thresholds: { excellent: 80, good: 60, poor: 30, critical: 0 },
  recomputeOn: [{ event: 'feature.used' }, { event: 'api.error' }, { schedule: '0 0 * * *' }],
});

Kite supports one health definition. Component weights must total 1. Scores and their weighted total are rounded and clamped to 0–100.

Computation types

TypeCalculation
event_frequencycount / target * 100, with optional minScore.
inverse_event_countmaxScore - count * penaltyPerEvent.
feature_adoptionDistinct used features divided by eligible configured features.
customA deterministic formula using event counts, numeric traits, and prior components.

Feature adoption reads feature or features event properties. With respectPlanFeatures, the eligible set comes from the customer's availableFeatures trait. Keep that trait synchronized with entitlement changes.

Custom components are evaluated by component ID in lexical order, so only reference a computed component whose ID sorts earlier. Formulas run in a restricted process and must be deterministic; Date and Math.random are unavailable.

Thresholds are validated metadata. The runtime does not assign labels from them, so define any segment or UI label explicitly from healthScore ranges.

Calibration workflow

  1. Choose a window matching the product's natural use frequency.
  2. Calculate a baseline from representative live customers.
  3. Compare component distributions for retained and churned cohorts.
  4. Remove redundant components and cap signals one customer can inflate.
  5. Run kite recompute --all --dry-run before persisting a changed model.
  6. Inspect a customer with kite health explain <customerId> after deployment.

Scheduled recomputation is needed for time-based decay when no new event arrives. Manual recompute always evaluates health, independently of recomputeOn.

On this page