Skip to content

Automation  ·  Customer success

How to build customer health signals

A score says 82 and the customer churns six weeks later. Here is the model behind a health signal you can defend, the prompts that build it, and what it takes to run in production.

Built with Tray Headless

  1. System Amplitude
  2. System Zendesk
  3. Step Score per category
  4. Step Back-test
  5. System Salesforce
Also Slack

Categories stay visible instead of collapsing into one number, and the weights are back-tested against accounts that actually churned.

The short answer

What is a customer health signal?

There are four parts to customer health: a small set of signals chosen because they predict churn instead of because they were available, category scores that stay visible instead of collapsing into one number, weights back-tested against customers who actually left, and alerts on movement instead of on level. The part that goes wrong most often is the single number. A score of 62 tells nobody what to do, and two accounts at 62 can need completely different conversations.

What matters here

  • Choose signals because they predicted churn in your data, not because they were easy to get.
  • Never collapse to one number alone. Two accounts scoring 62 can need entirely different conversations.
  • Back-test against customers who actually left. A score nobody validated is a shared opinion with a colour attached.
  • Alert on a category moving, not on a total crossing a line. The total moves slowly and hides the change.
  • Track whether flagged accounts actually churned. If they did not, the model is decoration.

Who this is for

You run customer success operations. There is a health score somewhere, nobody quite trusts it, and the accounts that churn were usually green the month before.

How it works in practice

The path from a customer going quiet to somebody doing something about it.

  1. 1

    Signals are gathered per category

    Usage, support, engagement and commercial, kept separate rather than merged on collection.

  2. 2

    Each category is scored on its own

    So a healthy product user with a support problem does not average out to fine.

  3. 3

    Weights come from a back-test

    Fitted against accounts that actually churned, not chosen in a workshop.

  4. 4

    The categories stay visible on the record

    Alongside the total, because the total says whether and the categories say why.

  5. 5

    Alerts fire on a category moving

    Not on the total crossing a threshold, which happens late and slowly.

  6. 6

    Every flag is tracked to an outcome

    Did the flagged account churn. That number decides whether anybody should trust this.

What a health signal is made of

Four parts, though the third is what separates a model from a colour.

Predictive signals

Chosen from what actually preceded churn in your history: usage decline, support escalations, champion departure, engagement gaps and payment behaviour.

Visible categories

Usage, support, engagement, commercial. Each scored and shown, because the reason is more actionable than the verdict.

Back-tested weights

Fitted against accounts that left. Weights chosen by committee encode what people believe, not what happened.

Outcome tracking

Whether flagged accounts churned, and whether unflagged ones did. The second number is the one that finds the missing signal.

The Tray Headless prompts

Paste these into Claude Code or Codex with the Tray Headless plugin installed. Each stage runs on its own. The systems named in them are the worked example rather than a requirement, and every prompt says so.

Once per project, run /tray-workflows:set-workspace to pick the workspace these build in. Point it at a sandbox first.

  1. 1

    Set up, then look at who actually left

    The history is the only honest source of weights.

    Headless skills build-workflow tray-patterns

    Use build-workflow. The systems in play are Snowflake and Salesforce,
    or whatever we run in those seats.
    
    Before building a score, pull the last two years of churned accounts and
    show me, for each, what the six months before looked like: usage trend,
    support volume and escalations, meeting frequency, payment behaviour, and
    whether a named champion left.
    
    I want to see which of those actually moved before churn and how far
    ahead. That is where the weights come from. Anything that did not move
    should not be in the model regardless of how sensible it sounds.
  2. 2

    Score categories separately, and keep them separate

    Averaging is how a real problem disappears.

    Headless skills build-workflow

    Use build-workflow. Score four categories independently:
    
      Usage: active users against seats, breadth, and direction of travel
      Support: ticket volume against the norm for that size, escalations,
      and satisfaction where we have it
      Engagement: days since a meeting, executive contact, champion still
      present
      Commercial: payment behaviour, contract value trend, open expansion
    
    Score each 0 to 100 and store all four on the account alongside the
    total.
    
    Do not let a good category hide a bad one. An account with usage at 90
    and support at 20 averages to fine and is not fine, and the categories
    are the only thing that shows it.
  3. 3

    Fit the weights against real churn

    Otherwise the model encodes what people believe instead of what happened.

    Fit the category weights against the churned cohort rather than choosing
    them in a workshop.
    
    Then back-test: run the scoring over historical data and check how many
    accounts that churned were flagged, how far in advance, and how many
    that were flagged did not churn.
    
    Report both error types. A model that flags everything catches every
    churn and is useless. A model that flags nothing looks precise and is
    also useless.
    
    Show me the back-test before this goes near a customer success team. A
    health score nobody validated is a shared opinion with a colour attached,
    and it takes one wrong call for people to stop looking at it.

    The false positive rate is the one that decides adoption. If CSMs chase five healthy accounts for every real one, they stop chasing.

  4. 4

    Alert on movement in a category

    The total moves late and slowly. Categories move first.

    Headless skills tray-gotchas

    Use tray-gotchas, then alert on movement instead of level:
    
      A category dropping more than a band in a period
      Two or more categories declining together, which is a stronger signal
      than one falling further
      Any decline on an account with a renewal inside two quarters
      A champion leaving, which should alert on its own regardless of score
    
    Route to the account owner and the customer success manager with which
    category moved and what changed inside it.
    
    Never alert only on the total. It moves last, by which point the
    conversation is a rescue, not a check-in.
  5. 5

    Track outcomes, and be willing to delete signals

    A model nobody measures becomes decoration within two quarters.

    For every flag, record what happened: nothing, intervention, saved,
    churned.
    
    Report quarterly: churn rate among flagged versus unflagged accounts,
    average warning time before churn, false positive rate per signal, and
    accounts that churned without ever being flagged.
    
    That last list is the most useful thing here. It is where the missing
    signal is, and it is the only way the model improves.
    
    Retire any signal whose weight fits to near zero on the back-test. A
    score built from twelve inputs where four do the work is harder to trust
    and no more accurate.
  6. 6

    Prove it works, then hand the weights over

    Because the model changes as the product and the segments do.

    Run the per-step schema checks and the whole-workflow audit before this
    touches production.
    
    Then open the same workflow in Tray Build so customer success operations
    can adjust the category weights and the alert bands in the visual canvas,
    and re-run the back-test after every change rather than trusting that it
    still holds.

What it connects to

Health is assembled from four systems and lands in the one where relationships live.

Snowflake

Hold the history the back-test runs against, and compute the category scores where that is cheap.

Reads and writes

Salesforce

Write the four category scores and the total as read-only fields, and read contract and renewal context.

Reads and writes

Zendesk

Read ticket volume, escalations and satisfaction, which is the support half of the score.

Reads

Amplitude

Read usage and its direction, which is usually the earliest signal that anything is wrong.

Reads

Gong

Read meeting frequency and whether an executive has been in the room recently.

Reads

Slack

Alert the account owner on a category moving, with the specific change instead of a new number.

Writes

Same build, other stacks

The design does not change if you run something else in one of these seats. The same prompts build it against Microsoft Dynamics 365, Google BigQuery, Microsoft Teams, Jira, Looker or HubSpot.

Named systems are the ones most teams run, not the only ones that work. Each is an authentication in your Tray workspace, referenced by name, so the workflow never holds a credential. Where we have a connector page, the name links to it.

Running it in production

People make retention decisions on this. An unvalidated score is worse than none.

It runs on the platform, not on your laptop

Scoring across four sources and the periodic back-test run on the same engine, with history for every score change.

Every score is reconstructable

The inputs and the weight version behind each score. When somebody disputes a red account, that is the answer.

Credentials are held by the platform, never hardcoded

Four systems, four authentications, each read-only and scoped. A scoring workflow needs to read a great deal and write almost nothing.

Customer success owns the weights

Category weights and alert bands open in Tray Build, with the back-test re-run after every change instead of assumed.

Outcomes are tracked or the model rots

Flagged against churned, every quarter. A health score nobody validates becomes decoration in about two quarters.

Questions people ask

Why not a single health score?

Because 62 tells nobody what to do, and two accounts at 62 can need completely different conversations. The total says whether and the categories say why.

Why back-test?

Because weights chosen in a workshop encode what people believe, not what happened. Fitting against accounts that actually left is the only thing that makes the score defensible when somebody disputes a red flag.

Why alert on movement, not the total?

Because the total moves last and slowly. A category dropping a band is an early warning; the total crossing a threshold usually means the conversation is now a rescue.

What is the most useful report?

Accounts that churned without ever being flagged. That list is where the missing signal is, and it is the only thing that improves the model.

When should a signal be removed?

When the back-test fits its weight to near zero. A score built from twelve inputs where four do the work is harder to trust and no more accurate.

Vibe-coding app guides

Vibe-code an entire app with Helix

This moves the data between systems. It does not give anybody a screen to work in. Build that app in Claude Code, Codex or Cursor, then deploy and run it governed on Tray Helix. Same kind of guide, same kind of prompts.

How to build a customer health dashboard (opens helix.tray.ai in a new tab)

Last reviewed September 2026.