Kataja Analytics is a Helsinki-based B2B software company – dashboards and reporting, roughly 500 mid-market accounts across the Nordics and Europe. Its customer success team runs a standard churn model on usage levels, trends and seat utilisation. It works. It catches the accounts whose logins taper off, whose report volume visibly declines before the cancellation email arrives.
It did not catch Bergvik Systems AB. Bergvik – 31 seats, €12,426 a year – used the product normally right up until it left. What moved was the tone of four support tickets over thirteen months, each longer and more careful than the last, each ending with some version of “no need to treat this as urgent”. Two colleagues quietly went back to doing the board pack in Excel. Nobody escalated, nobody used a harsh word, and the account cancelled anyway.
This page demonstrates a second detector built for that shape of churn: an agent that reads each account’s ticket history in order and scores the relationship, combined with the usage model through one small, explainable layer. The question that matters commercially is whether the combination catches more than either detector alone, and what the difference is worth. You can check that claim yourself below – Bergvik’s full file, tickets included, is open for inspection.
Every account gets two opinions: the usage model’s, from the numbers, and the ticket agent’s, from what customers actually wrote. The sliders blend those opinions into one live ranking – each dial runs from 0 (that channel off) to 100 (its full weight in the fitted model), and the leaderboard re-sorts as you drag. The presets jump to each detector on its own, or to the combination as fitted.
Try this – drag the ticket-sentiment weight to zero and watch which companies drop off the list. Those are the quiet leavers a usage-only model never shows you.
| # | Account | ARR | ML | Tickets | Blended |
|---|
A ranking is only useful up to the point where the review effort runs out. A customer-success team that can work through a hundred accounts a cycle needs to know what a list of that length actually catches – and what falls just below the line. The slider sets the budget; the counters follow the mixer’s current blend.
Try this – tighten the budget to 50 and watch how much ARR drops out of reach; then switch on “Reveal outcomes” above to see how many of the flagged accounts really left.
Every account, plotted by where each detector ranks it. The dashed lines mark each layer’s own top-100 watch-list, independent of the mixer above. Top-left, both flag the account – and where they agree they are right almost every time. Bottom-left, only the usage model sees trouble: the visible faders. Top-right, only the tickets do: Bergvik’s kind, healthy on every dashboard while the relationship sours in writing. Bottom-right, neither. Most of those accounts are genuinely fine, but some churn is invisible to both layers, and we count that honestly.
Try this – click any dot to open that account’s file below; the top-right quadrant is where the interesting reading is.
Click any account in the leaderboard or the figure above and read the tickets yourself – this is the evidence the usage model cannot see. Each file shows the account’s usage curves, its full ticket history in order, and the agent’s verdict.
Marked against the answer key, the combination catches more of the accounts that matter and misses fewer euros. The money segment is the quietly unhappy – Bergvik’s type, 46 accounts engineered to look healthy on every usage metric while the relationship erodes in the ticket queue:
| Method | Quietly-unhappy accounts caught, of 46 |
|---|
Attach revenue. €6.53M of ARR sat inside accounts that actually churned. The text layer surfaces €1.34M of churned ARR the usage model alone does not – accounts that looked healthy on every dashboard metric until the invoice stopped renewing. Usage returns the favour in the other direction, worth €703K in accounts the text layer under-weighted. Neither layer subsumes the other, which is why the finding is the combination.
And thirty accounts here churn for reasons invisible in the product – an acquisition, a budget cut, a champion leaving. Two of the thirty survive into the combined top-100, roughly what chance would produce, because there is no signal for either method to find. Any model claiming to catch everything should be asked what its number looks like on that row.
Your ticket system already holds this signal; it costs nothing extra to collect. The method transfers to any account base with a support history: a classical model where the numbers are strong, a reading layer where they are silent, and one small, explainable model combining the two. The write-up documents every miss as carefully as every catch – the misses tell you where the ceiling sits.
Read the long-form case study · Code and dataset · Contact Hapax