The Churn Early Warning System
Spot at-risk clients before they ask to pause -- how the churn system works.
What it is
The Churn Early Warning System runs every day and computes a risk score for every active BTT client. High and medium-risk clients appear as colour-coded cards on the Admin and Management dashboard. Its purpose is to surface clients at risk of churning before it happens so the AM can intervene.
How scoring works
The cron at /api/cron/churn-check (daily 03:00 UTC) pulls each active client and scores them on three signals:
- Negative-tone email signals: scans recent HubSpot email threads for keywords associated with dissatisfaction, pausing, or cancellation intent.
- Email volume spike: detects an unusual increase in inbound emails from the client (can indicate active complaints).
- Fathom meeting gap: checks whether the client has had a face-to-face meeting recently. Clients with no Fathom meeting on record at all score 8 points if they have been active for 28+ days (established client with no meeting is a high-risk signal), or 3 points if they joined less than 28 days ago (new clients are not expected to have a meeting record yet). The clients.start_date column gates this discrimination.
Scores are written to the churn_alerts table with the full list of signals that fired. The dashboard widget renders high-risk (red) and medium-risk (amber) cards for Admin and Management roles.
Weekly summary
Every Monday at 09:20 UTC the /api/cron/weekly-churn-summary cron posts the top-10 at-risk clients to #bristechtonic-jarvis Slack with risk icon, score, AM name, and all signals.
What the system does not do
- It does not automatically take action on any client. It surfaces information only.
- It does not use GSC or GA4 traffic drops as a signal (too expensive on every daily run).
- It does not distinguish between a client who is unhappy and one who is simply busy -- that judgement belongs to the AM.
Relevant files
- Cron route: app/api/cron/churn-check/route.js
- Dashboard widget: app/(hub)/page.js (churn cards section)
- Table: churn_alerts (Supabase)
- Weekly summary: app/api/cron/weekly-churn-summary/route.js