If a customer churns, you probably missed the signals.
Here's how to build a simple system designed to catch those signals early and alert you before churn happens.
Open PostHog. Go to: PostHog dashboard
Next, instrument your product to capture important customer activity events using the PostHog SDK or API.
Good examples:
* user_logged_in
* project_created
* report_exported
* teammate_invited
Avoid tracking random clicks that do not help you understand customer health.
Here are some examples:
Those usually create noise. The goal is to track the actions active customers do again and again.
Customers who are about to churn often stop paying attention to failed payments.
Inside Make:
Now, select these events:
* invoice.payment_failed
* customer.subscription.updated
These events help you catch accounts that may be about to churn. A failed payment is usually not just a billing issue. A lot of the time, a failed payment is a sign that the customer is disengaging.
Still inside Make:
Next:
IF:
- user has not logged in for 7 days
OR
- product usage decreases by more than 50% compared to the week before
OR
- team invites stop
OR- Stripe payment fails
THEN:
- Flag the account
- Notify the team
This becomes a simple churn agent. A simple churn setup is enough for most startups.
Now, add OpenAI to Make.
Inside Make:
Map the customer activity data into the prompt. For example:
Inside Make, map those fields directly into the OpenAI prompt. Use this prompt (or similar):
Analyze this SaaS account.
Signals:
- Days since last login: {days_since_last_login}
- Weekly exports: {weekly_export_count}
- Team invites this week:{weekly_team_invites}
- Failed payment status: {failed_payment_status}
Return:
- Churn risk
- Likely issue
- Suggested next step
- Short outreach email
This gives the AI enough context to generate much more useful recommendations.
Add another Make module.
Inside Make:
Now, send the OpenAI response into a Slack channel.
Here's an example alert:
HIGH CHURN RISK
Customer: {customer email}
Issues:
- Inactive for 9 days
- Exports dropped sharply
- Payment failed
Suggested next step: Reach out personally and offer the customer onboarding help.
Slack alerts work really well because most people already spend time in Slack.
Now, create an internal churn form in Jotform. Go to:
Name the form: Churn Review
Add a few fields:
After a churned account gets reviewed, fill out the form manually. This is less about documentation and more about learning. After a while, common churn reasons will become easier to spot.
Once people start filling out the form, create a Jotform AI Agent.
Inside Jotform:
Choose:
Next, add churn-related documentation and support materials to the AI Agent knowledge base.
In the agent setup, go to the Train or Knowledge Base section and add materials like:
Add instructions for how the agent should respond. Paste this (or similar):
Analyze churn feedback submissions.
Identify:
- most likely churn reason
- feature complaints
- onboarding issues
- pricing complaints
Keep the answers short
Now, the AI Agent can help review churn feedback submissions.
This is important. Do not fully automate retention. AI is useful for:
But customers still respond best to human outreach. Especially in B2B SaaS. Simple emails work best.
Here’s an example:
Hey Alex,
Noticed activity dropped recently.
Wanted to make sure the team is not running into any issues.
Happy to help if needed.
Messages like this sound natural, which is why they get replies.
And that’s it... a simple way to catch churn before it happens.
Love this Aytekin!
Practical and specific. I set this up for our app and the Stripe + PostHog combo catches problems days before invoices fail. Big win: keep outreach personal, not automated. Thanks for the clear wiring.
Saved this one. Most "catch churn early" posts stop at the idea and leave you to figure out the wiring. The fact that you named the actual tools and the exact Stripe events to watch makes it something useful. Thanks for writing the whole thing out.
This is exactly the kind of system I wish I had set up earlier. The OpenAI prompt structure in Step 4 is particularly useful — mapping specific behavioral signals directly into the prompt rather than dumping raw data is something most people skip. One thing I'd add: for solo founders without PostHog set up yet, even a simple "last login" timestamp in your own DB + a daily cron job can catch 80% of what you described here before you need the full stack.
Agree with the threshold point above — and I'd add that even when usage data does flag churn risk, it's often too late to understand why. Sentiment in support tickets/feedback tends to shift before the behavioral signals do, and it also tells you the reason, not just that something's wrong. Be curious whether anyone here is combining qualitative and behavioral signals rather than picking one.
The part I'd push on: this whole thing runs on fixed thresholds — 7 days no login, 50% drop — and fixed thresholds are what get churn alerts muted by week three. oghabayen touched it above and it's the real crack.
a "50% drop" means nothing without a baseline. a daily-active account dropping 50% is a fire; a use-it-every-other-Friday account dropping 50% is Tuesday. same alert, opposite meaning — and if both fire the same way, you stop trusting all of them. the threshold has to be relative to that account's rhythm, not a global number.
and the deeper version of the champion point arcadino raised: usage is lagging because it measures the symptom. the leading signal isn't "usage dropped 50%," it's "the person who drove adoption went quiet." that predicts churn weeks before the aggregate moves.
Honestly, for most startups here steps 1-7 are premature. under ~50 accounts you hold every customer's health in your head, and a calendar reminder to check on anyone gone quiet beats the whole stack. the step-8 "keep it human" point is the one that survives at every scale anyway.
Agreeed hooga!
Fixed thresholds cause alert fatigue. I use each account’s baseline (rolling 4-week median) then trigger on relative drops. Cuts noise and catches real problems faster.
The point about skipping button_hovered and tracking real events like teammate_invited saves you from drowning in noise that looks like data. For my smaller apps I just treat one repeated core action as the health signal since a full PostHog stack is overkill at that size. At what user count did this setup start paying off enough to justify all the tooling?
Cancel click is a receipt, not the decision. real signal is in the 7 days before - usage dropped, that feature request they filed quietly disappeared. by the time Stripe fires, you're already behind.
Churn is a leading indicator. The founders who catch it earliest aren't the smartest —
they're the ones who actually talk to customers who leave. Most SaaS teams avoid that
conversation. Which signal do you watch before revenue drops?
Great breakdown.. the point about failed payments being a disengagement signal, not just a billing issue, really resonated. Bookmarking this..
The champion-leaving signal is something I don't see enough tools track. Usage drops are lagging — by the time you see a 50% weekly drop, the decision to churn is often already made. But when the person who originally pushed to adopt your product goes quiet or changes roles, that's usually much earlier in the process.
One thing I'd add: in B2C or consumer fintech, the equivalent of the "champion leaving" is when a power user stops their most habitual action (the one that got them hooked originally). That first missed habit tends to predict disengagement faster than any aggregate usage metric.
Did you find that the AI-generated outreach drafts needed much editing before you'd actually send them, or were they usable close to out of the box?
Most drafts were usable out of the box but I always tweak tone and add one personal line about usage. Keeps messages short and human.
Really like that step 8 isn't an afterthought here. A lot of churn tools stop at "detect and alert" and skip the part that actually saves the account, a real human reaching out before the customer's already decided to leave.
Curious about the 50% usage drop threshold though. Wouldn't that flag a lot of normal accounts too, like a team that's just slower during a holiday week? Seems like the threshold would need to flex per customer's normal baseline, or you'd end up with alert fatigue pretty fast.
The most common failure I've seen with setups like this isn't the tracking — it's what happens after the alert fires.
You get a Slack message saying 'User X hasn't logged in for 7 days.' Then what?
If there's no response playbook attached to each alert type, teams either over-respond (emailing every flagged user) or under-respond (alert fatigue, ignore everything).
What worked for us: attach a specific next action to each signal before you build the trigger.
Failed payment → automated email with updated card link (no human needed)
7 days no login → personal email from founder within 24h
50% drop in usage → trigger a customer check-in call
Build the response logic at the same time as the detection logic. Otherwise the alerts just become noise.
this is a good idea
The automation tells you when. A human still has to show up. Most teams nail the first part and skip the second.
Spot on about failed payments being an engagement signal, not just a billing issue. Love the Make + Slack setup to catch this early—super practical! Definitely bookmarking this.
At early stage I'd skip most of this stack and just call the accounts that go quiet. The signal that predicted churn best for us was never usage dipping, it was the champion who onboarded an account leaving the company or going dark. Usage drops are lagging, the person leaving is the leading indicator.
Thank you
This really resonates.
I've started wondering whether churn signals look a lot like sales signals—they're usually visible long before the outcome, but they rarely get noticed in time.
What's been the earliest predictor you've found?
the system for spotting the churn is what it's all about 100%
Yes, but many people aren’t concerned about this and continue to focus on acquiring new clients.