Le signal de churn le plus fiable dont dispose une équipe CS, c’est l’usage produit qui s’effondre, et la manière la plus courante de manquer ce signal, c’est que personne ne regarde la bonne semaine. Au moment où un QBR fait remonter la baisse, le compte est silencieux depuis deux mois. Ce workflow comble cet écart avec le mécanisme le plus réduit possible : un flow n8n hebdomadaire qui lit le nombre d’utilisateurs actifs de chaque compte depuis Amplitude, compare la semaine dernière à celle d’avant, et envoie un message direct Slack au CSM propriétaire lorsque la baisse franchit un seuil que le lead CS Ops contrôle par compte. Il fait une seule chose —faire remonter une baisse d’usage d’une semaine sur l’autre tant qu’elle est encore le problème de cette semaine— et il le fait sans un dashboard que personne n’ouvre.
Le bundle de l’artifact se trouve dans apps/web/public/artifacts/usage-drop-alert-n8n/. L’export n8n est usage-drop-alert-n8n.json et le guide des credentials, du schema et de la vérification est _README.md. Les deux sont une lecture obligatoire avant d’activer le schedule, car le bundle est livré avec des credentials placeholder et deux tables Postgres qui doivent exister avant la première exécution.
Quand l’utiliser
Utilisez-le lorsque vous êtes un lead CS Ops gérant un book de comptes qui a dépassé le stade où l’on suit à l’œil un dashboard d’usage —quelque part au-delà de 50 comptes par CSM, où personne ne peut garder tout le portefeuille en tête. Il vous faut Amplitude (ou un outil de product analytics vers lequel le nœud HTTP peut être repointé) qui suit un signal d’utilisateurs actifs par compte, un workspace Slack, et un endroit pour stocker des seuils par compte. Le flow est le bon choix lorsque l’organisation CS fait déjà confiance à l’usage produit comme indicateur avancé mais n’a aucun mécanisme qui pousse le signal vers un humain avant le prochain QBR.
Il s’intègre particulièrement bien comme la couche initiale peu coûteuse sous un modèle de santé plus lourd. Si vous exécutez déjà le customer health score composite en n8n, ce flow en est le complément à réaction rapide : le score composite se recalcule chaque nuit et vous dit où se situe un compte, tandis que cette alerte se déclenche chaque semaine et vous dit ce qui vient de bouger. Beaucoup d’équipes montent l’alerte en premier parce que c’est une après-midi de travail et que cela gagne la confiance en quelques jours, puis passent au composite une fois que les CSM agissent sur les pings.
Quand NE PAS l’utiliser
Passez votre chemin si un CSM peut lire tout le portefeuille à la main. En dessous d’environ 30 comptes par CSM, un humain qui scanne le dashboard d’usage le lundi matin attrape les mêmes baisses avec plus de contexte, et le coût en faux positifs d’un seuil automatisé n’en vaut pas la peine. Le flow gagne sa place par le volume, pas par l’ingéniosité.
Passez votre chemin si votre tagging au niveau compte dans Amplitude n’est pas fiable. Tout le flow repose sur le fait que gp:account_id (ou votre propriété utilisateur équivalente) soit défini de manière cohérente sur chaque événement. Si les comptes sont taggés de façon incohérente —certains événements portent la propriété, d’autres non— le nombre d’actifs hebdomadaires n’a aucun sens et l’alerte se déclenche sur un artefact de tagging, pas sur un changement de comportement. Corrigez d’abord la taxonomie ; une alerte sur des données sales est pire qu’aucune alerte, car elle porte l’autorité d’un chiffre.
Passez votre chemin si la baisse qui vous importe est au niveau du siège ou de la fonctionnalité plutôt qu’au niveau du compte. Ce flow surveille un signal —les actifs uniques hebdomadaires par compte— et une baisse de 40 % des actifs totaux peut masquer un compte en bonne santé qui a simplement perdu un power user pendant une semaine de vacances. Si votre risque de churn réside dans l’abandon d’une fonctionnalité précise ou dans un seul champion nommé qui se tait, il vous faut un cohort par-fonctionnalité ou par-utilisateur, qui est un flow différent (plus lourd). Et passez votre chemin si l’équipe n’a aucun playbook sur ce qu’il faut faire quand une alerte de baisse se déclenche ; une notification sans action suivante définie entraîne les gens à l’ignorer.
Setup
Le setup est documenté de bout en bout dans apps/web/public/artifacts/usage-drop-alert-n8n/_README.md. La version courte : importez le JSON dans n8n via Settings → Import From File, créez les trois credentials placeholder (Postgres, Amplitude Basic auth, Slack bot token), créez les deux tables Postgres à partir du DDL dans le README (accounts_in_scope et usage_alert_history), seedez un compte canary, et exécutez la séquence de vérification en huit étapes avant d’activer le schedule. À partir d’une installation n8n propre, prévoyez 45 à 90 minutes —la majeure partie consacrée à confirmer que la requête de segmentation Amplitude correspond à votre taxonomie d’événements et que l’application Slack peut envoyer des DM aux utilisateurs de votre workspace.
La table accounts_in_scope est l’endroit où vit la politique par compte, et bien la régler fait la différence entre une alerte utile et un bot mis en sourdine. Chaque ligne porte drop_threshold_pct (le pourcentage de baisse qui déclenche une alerte) et min_baseline_events (le plancher d’utilisateurs actifs en dessous duquel le compte est trop petit pour être jugé). Les comptes enterprise fonctionnent souvent avec un seuil plus serré —une baisse de 25 % sur un compte de 200 sièges mérite un coup d’œil— tandis que les comptes self-serve tolèrent plus de bruit et tournent à 50 %. Garder ceux-ci comme colonnes de table plutôt que comme constantes hard-codées signifie que réajuster est un seul UPDATE, pas un redéploiement.
Ce que le flow fait réellement
Le cron se déclenche le lundi à 09:00 en America/New_York (l’expression est 0 13 * * 1 —13:00 UTC— donc confirmez que le timezone du workflow est défini). Le lundi matin est délibéré : la semaine précédente est entièrement close, il n’y a donc pas de comparaison de semaine partielle qui lirait chaque lundi comme une baisse. Pull Accounts In Scope lit jusqu’à 500 comptes actifs ayant un Slack id de CSM défini ; les comptes sans propriétaire sont filtrés en SQL puisqu’il n’y a personne à notifier. Batch Accounts (20/group) les découpe en groupes pour que les appels Amplitude parallèles restent sous le plafond de concurrence de la Dashboard REST API, avec une attente d’une seconde entre les batches.
Amplitude — Weekly Actives (14d) appelle l’endpoint /api/2/events/segmentation avec i=7 (buckets hebdomadaires) sur une fenêtre de 14 jours, segmenté sur la propriété gp:account_id du compte. Cela renvoie deux points hebdomadaires : la semaine dernière et celle d’avant. Compute WoW Drop est la seule véritable logique du flow et prend deux décisions. D’abord, le garde-fou de bruit : si le nombre d’actifs de la semaine précédente est inférieur à min_baseline_events, le compte est marqué skipped_low_baseline et n’alerte jamais —passer de quatre actifs à deux est une baisse de 50 % et du pur bruit. Ensuite, le seuil : il calcule (week_before - last_week) / week_before en pourcentage et, seulement si cela atteint ou dépasse le drop_threshold_pct du compte, marque la ligne alert avec une raison lisible comme « les actifs hebdomadaires ont chuté de 47 % (de 120 à 64) par rapport à la semaine précédente ».
Crosses Threshold? route les lignes d’alerte plus loin ; tout le reste va directement au throttle. Lookup Recent Alert vérifie ensuite usage_alert_history pour toute alerte sur ce compte au cours des 14 derniers jours, et Outside Cooldown? supprime la répétition s’il en existe une. C’est le second garde-fou contre la fatigue : une baisse soutenue pingerait sinon le CSM chaque lundi jusqu’à ce que l’usage se rétablisse, ce qui l’entraîne à ignorer le bot. Avec le cooldown, une vraie baisse ping une fois, et le CSM devient propriétaire du suivi à partir de là.
Les lignes survivantes atteignent Slack — DM Owning CSM, qui poste un message Block Kit directement vers le Slack user id du CSM avec le nom du compte, le segment, les nombres d’actifs avant/après, le pourcentage de baisse, et le seuil qui a déclenché. Persist Alert (idempotent per week) écrit l’alerte dans usage_alert_history avec une clause ON CONFLICT clé sur (account_id, date_trunc('week', alerted_at)), de sorte qu’une exécution réessayée met à jour la ligne existante au lieu d’envoyer un DM au CSM deux fois, et estampille last_alerted_at sur le compte pour la lecture de cooldown en chemin rapide.
Réalité des coûts
Ce flow est presque gratuit à exécuter. Il n’y a aucun appel LLM —la comparaison est de l’arithmétique dans un nœud Code, donc le seul coût est le quota d’API et le temps d’exécution n8n. Par compte et par semaine, le flow fait une lecture de segmentation Amplitude, au plus une écriture Slack, et deux ou trois requêtes Postgres. La Dashboard REST API d’Amplitude ne facture pas à l’appel sur les plans payants ; la contrainte est sa faible limite de concurrence, ce qui explique précisément pourquoi le batch size est de 20 avec un throttle d’une seconde. Pour 500 comptes, l’exécution complète se termine en environ trois à six minutes sur le petit executor de n8n Cloud, dominée par les lectures Amplitude sérialisées. Le chat.postMessage de Slack est rate-limited à environ un message par seconde par contexte de canal, confortablement en dessous de ce dont un volume d’alerte hebdomadaire a besoin.
Le vrai coût est humain, et c’est le coût que vous cherchez à réduire : un lead CS Ops passe peut-être une heure par trimestre à réajuster les seuils à mesure que les segments évoluent, contre l’alternative où les CSM passent chacun 20 à 30 minutes par semaine à scruter des dashboards à l’œil (ou, plus souvent, à ne pas le faire et à l’apprendre au QBR). Sur une équipe de 10 CSM, cela représente environ 40 à 50 heures par trimestre de scan manuel remplacées par une heure de maintenance de seuils —et ce scan attrapait de toute façon les baisses avec un mois de retard.
À quoi ressemble le succès
Surveillez trois chiffres au premier trimestre. D’abord, le taux d’action sur les alertes —la part des DM qui débouchent sur un touch CSM enregistré (un email, un appel pris, une note) dans les cinq jours ouvrés. Sondez ou instrumentez ceci ; visez au-dessus de 60 % à la fin du premier mois. Un taux d’action sous 40 % signifie que le seuil est trop lâche et que le bot crie au loup —remontez drop_threshold_pct pour les segments bruyants. Ensuite, le lead time jusqu’à l’intervention —pour les comptes ayant ensuite churné ou s’étant contractés, mesurez de combien de jours l’alerte de baisse d’usage a précédé le premier outreach du CSM par rapport à la baseline historique du « découvert au QBR ». Tout l’enjeu est de faire passer ce chiffre d’environ 60 jours à moins de 14. Enfin, le taux de suppression —la part des comptes ayant franchi le seuil mais retenus par le cooldown. Un chiffre sain est bas et stable ; un taux de suppression en hausse signifie qu’un cohort est en déclin soutenu et que l’alerte hebdomadaire n’est plus le bon outil —ces comptes ont besoin du customer health score composite et d’un save play, pas d’un ping de plus.
Versus les alternatives
L’alternative par défaut est l’alerting propre à Amplitude —ses monitors Anomaly et Threshold peuvent surveiller un chart et déclencher vers Slack ou email. Si vous avez besoin d’exactement une alerte globale (« les actifs hebdomadaires totaux ont baissé »), utilisez le monitor natif d’Amplitude ; c’est moins de travail que de monter n8n. La raison d’être de ce flow est le routage par compte : les monitors d’Amplitude alertent sur un chart, pas sur un mapping compte-vers-CSM, donc un monitor au niveau portefeuille ne peut pas dire au CSM propriétaire que son compte a baissé. Pour obtenir un routage par-compte, par-propriétaire avec Amplitude seul, vous finissez par construire un monitor par compte, ce qui ne passe pas l’échelle au-delà d’une poignée. Ce flow garde la carte compte-vers-CSM et les seuils par compte dans une table que vous possédez et route en conséquence.
Une deuxième alternative est les alertes d’usage intégrées de votre CSP —Gainsight, Catalyst, ChurnZero, Vitally, Planhat et Totango sont tous livrés avec une forme de trigger de baisse d’usage. Si vous exécutez déjà un CSP et y canalisez l’usage produit, utilisez le trigger natif —les données y sont déjà et le routage vers le CSM est déjà câblé. Ce flow est pour l’équipe qui a son product analytics dans Amplitude mais n’a pas encore centralisé l’usage dans un CSP, ou dont le CSP a un retard d’un cycle de sync sur les données d’usage d’Amplitude. C’est le pont qui livre l’indicateur avancé avant que la rollup du CSP ne rattrape.
Une troisième alternative est un script DIY sur un cron —un job Python tapant l’API Amplitude et l’API Slack. Il est plus rapide d’écrire la première version que de câbler le flow n8n, mais il porte la charge de rotation des credentials dans le code, n’a pas de sémantique de retry out of the box, et est invisible pour le lead CS Ops qui n’est pas ingénieur. La version n8n échange la flexibilité brute contre une UI de credentials, des retries intégrés, et un flow visuel qu’un non-ingénieur peut lire et réajuster. Choisissez le DIY si CS Ops dispose d’un ingénieur permanent ; choisissez le flow n8n si la personne qui règle les seuils est la même que celle qui lit les alertes.
Points de vigilance
Un artefact de tagging se lit comme une falaise d’usage. Si l’instrumentation produit change —un événement est renommé, la propriété account_id cesse d’être définie sur une surface— chaque compte de cette surface affiche une chute à zéro et le bot envoie un DM à tous les CSM d’un coup. Garde-fou : avant d’activer, interrogez le compte distinct de comptes avec gp:account_id non-null des deux dernières semaines et confirmez qu’il est stable ; et traitez un pic de volume d’alerte sur la même semaine à travers de nombreux comptes comme un incident d’instrumentation, pas une vague de churn —la table usage_alert_history rend ce pic visible d’un coup d’œil.
Les petits comptes génèrent des baisses fantômes. Un compte passant de quatre actifs hebdomadaires à deux est une baisse de 50 % et ne signifie rien. Garde-fou : le plancher min_baseline_events dans accounts_in_scope marque tout compte sous le seuil de la semaine précédente comme skipped_low_baseline et n’alerte jamais dessus. Réglez le plancher par segment —self-serve peut tourner avec un plancher de 5, enterprise en a rarement besoin.
Les baisses soutenues spamment le CSM. Sans suppression, un compte qui baisse et reste bas se déclencherait chaque lundi jusqu’à se rétablir. Garde-fou : Lookup Recent Alert plus le cooldown de 14 jours dans Outside Cooldown? garantit une alerte par événement de baisse ; le CSM devient propriétaire du suivi après le premier ping, et un compte encore en déclin remonte dans le customer health score composite, pas dans une alerte répétée.
Les retries envoient un DM en double. Une défaillance de nœud en milieu de batch qui déclenche un retry n8n pourrait envoyer le DM Slack deux fois. Garde-fou : usage_alert_history a un index unique sur (account_id, date_trunc('week', alerted_at)) et Persist Alert utilise ON CONFLICT ... DO UPDATE, donc la deuxième tentative met à jour la ligne hebdomadaire existante au lieu d’en insérer une nouvelle —et comme l’envoi Slack précède le persist, la lecture de cooldown au retry l’attrape.
Le DM arrive et rien ne se passe. Une alerte sans étape suivante définie est du bruit horodaté. Garde-fou : c’est un garde-fou de processus, pas de code —associez le déploiement à un playbook d’une ligne (« DM de baisse d’usage → vérifier le compte dans votre CSP → enregistrer un touch dans les cinq jours ouvrés ») et suivez le taux d’action ci-dessus. Si le taux d’action est bas, le correctif est le playbook ou le seuil, pas plus d’alertes.
Stack
n8n —orchestration, le schedule hebdomadaire, retries, gestion des credentials, et un flow visuel qu’un lead CS Ops peut réajuster sans ingénieur
Amplitude —la source d’usage produit ; actifs uniques hebdomadaires par compte via l’endpoint events/segmentation de la Dashboard REST
Slack —le canal de livraison ; un DM Block Kit vers le user id du CSM propriétaire (repointable vers un canal partagé)
Postgres —accounts_in_scope pour les seuils par compte et le routage CSM, usage_alert_history pour le cooldown et la clé d’idempotence
# Usage-drop alert for CSMs — n8n flow
## What this flow does
This flow runs every Monday at 09:00 in `America/New_York` and checks every active account for a week-over-week drop in product usage. For each account it pulls two weekly buckets of unique active users from Amplitude (last week and the week before), computes the percentage drop, and compares it against a per-account threshold stored in Postgres. Accounts whose drop crosses the threshold — and that are not inside a 14-day cooldown from a prior alert — trigger a Slack direct message to the owning CSM naming the account, the before/after active-user counts, and the percentage drop. Every alert is logged to a history table so a sustained dip pings the CSM once, not every week.
The flow is deliberately small: one external read (Amplitude), one decision (threshold), one suppression check (cooldown), one notification (Slack), one write (history). It is the leading-indicator companion to a full composite health score, not a replacement for one.
## Import
In n8n: open **Settings → Import From File → select `usage-drop-alert-n8n.json`**. After import, open the workflow and confirm the timezone in **Workflow Settings** is `America/New_York` (it ships set, but reconfirm — the schedule trigger and the cron's `13:00 UTC` expression both assume it). Activate the workflow only after credentials are wired and the verification run below has passed.
## Credentials
Two placeholder credentials are referenced by name in the export. Create each in n8n under **Credentials → New** and map the matching `PLACEHOLDER_*_CRED_ID` reference on first open. (Postgres is the third — it backs the state tables and is also referenced by name.)
### `PLACEHOLDER_POSTGRES_CRED_ID` — Postgres — usage-alert-state
Used by three nodes: `Pull Accounts In Scope`, `Lookup Recent Alert`, and `Persist Alert (idempotent per week)`. Point this at a Postgres database you control. Required tables:
```sql
CREATE TABLE accounts_in_scope (
account_id text PRIMARY KEY,
account_name text NOT NULL,
amplitude_project_id text,
segment text,
active boolean NOT NULL DEFAULT true,
drop_threshold_pct int NOT NULL DEFAULT 40, -- per-account % drop that triggers an alert
min_baseline_events int NOT NULL DEFAULT 10, -- floor below which the account is too small to judge
csm_slack_user_id text, -- Slack user id of the owning CSM (e.g. U0123ABCD)
last_alerted_at timestamptz
);
CREATE TABLE usage_alert_history (
account_id text NOT NULL,
alerted_at timestamptz NOT NULL DEFAULT now(),
week_before int,
last_week int,
drop_pct int,
threshold int,
reason text
);
-- Idempotence key: one row per account per week, so retries do not double-log or double-DM.
CREATE UNIQUE INDEX usage_alert_history_week_uniq
ON usage_alert_history (account_id, date_trunc('week', alerted_at));
```
### `PLACEHOLDER_AMPLITUDE_CRED_ID` — Amplitude — API key:secret (Basic)
Amplitude's Dashboard REST API uses HTTP Basic auth where the username is the project **API Key** and the password is the project **Secret Key**. Find both in Amplitude under **Settings → Projects → [your project] → General**. In n8n create a **Basic Auth** credential: username = API Key, password = Secret Key. The flow calls the `/api/2/events/segmentation` endpoint, which needs no extra scope beyond a valid key pair. Note the endpoint returns event-segmentation series; the node's query segments on a `gp:account_id` user property — rename that to whatever account identifier your Amplitude taxonomy uses, and replace the `_active` event with your own activity event if you do not track a synthetic `_active` event.
### `PLACEHOLDER_SLACK_CRED_ID` — Slack — bot token
In your Slack workspace under **api.slack.com/apps**, create an app with a bot user and the scopes `chat:write` and `im:write` (the latter is required to open a DM channel with a user). Install the app to the workspace and copy the bot token (`xoxb-...`). Store it as a header credential with header name `Authorization` and prefix value `Bearer `. Because the flow DMs the CSM by Slack user id, each CSM must have **"Allow users in your workspace to send you direct messages"** enabled and the app must not be blocked. If your org restricts app DMs, point the `channel` field at a shared channel such as `#cs-usage-alerts` and tag the CSM in the message text instead.
## First-run verification
Run the flow manually before activating the schedule. This sequence proves each branch without spamming CSMs.
1. **Seed one canary account.** Insert a single row into `accounts_in_scope` with a real `account_id` that exists in Amplitude, your own Slack user id in `csm_slack_user_id`, `drop_threshold_pct = 1` (so any drop fires), and `min_baseline_events = 1`.
2. **Run `Pull Accounts In Scope` in isolation.** Confirm the canary row comes back. If empty, check `active = true` and that `csm_slack_user_id` is non-null (the `WHERE` clause filters out null Slack ids).
3. **Run `Amplitude — Weekly Actives (14d)`.** Confirm a non-empty `data.series` array with at least two weekly values. A 400 usually means the `gp:account_id` property name or the event name does not match your taxonomy; a 401 means the Basic auth key/secret pair is wrong.
4. **Run `Compute WoW Drop`.** Confirm `week_before`, `last_week`, `drop_pct`, and `status` are populated. Temporarily hand-edit the canary's Amplitude data (or pin a fixture) so `last_week` is well below `week_before` and confirm `status` becomes `alert`. Then set `min_baseline_events` above `week_before` and confirm `status` becomes `skipped_low_baseline` — that proves the noise guard works.
5. **Check the cooldown path.** With `usage_alert_history` empty, `Outside Cooldown?` should route to the Slack node. Manually insert a row into `usage_alert_history` for the canary dated yesterday, re-run, and confirm `Outside Cooldown?` now routes to the throttle (suppressed). Delete the test row afterward.
6. **Fire one real DM.** With the cooldown clear, let the flow run end-to-end on the canary. Confirm you receive the Slack DM with the account name, the before/after counts, and the drop percentage, and that one row landed in `usage_alert_history`.
7. **Re-run the same day.** Confirm no second DM arrives and `usage_alert_history` still has exactly one row for the week (the `ON CONFLICT` clause is doing its job).
8. **Restore real thresholds.** Set `drop_threshold_pct` and `min_baseline_events` back to production values (40 and 10 are sensible defaults) before activating the schedule.
If any step fails, fix it before activating. A weekly cron that DMs CSMs about phantom drops will train them to mute the bot inside a month — the noise guard and the cooldown exist specifically to keep that from happening.