Free, open-source churn prediction for SaaS -- plug in your data and know who's leaving before they do
CHURNGUARD AI -- RISK SUMMARY
====================================================
Total customers analyzed: 487
Customers at risk (>=30%): 74 (15%)
Critical risk (>=70%): 23 customers
High risk (50-70%): 31 customers
REVENUE AT RISK
Critical segment MRR: $18,420
High segment MRR: $11,340
Total MRR at risk: $29,760
Estimated ARR at risk: $357,120
PROJECTED RETENTION VALUE
At 20% save rate: $5,952 MRR / $71,424 ARR recoverable
====================================================
customer_id monthly_revenue churn_probability risk_tier mrr_at_risk
cust_0137 999.00 87.4% Critical 873.13
cust_0294 399.00 79.8% Critical 318.40
cust_0411 399.00 75.6% Critical 301.64
cust_0058 149.00 91.2% Critical 135.89
cust_0203 149.00 82.3% Critical 122.63
| ChurnGuard AI | Gainsight | ChurnZero | Generic GitHub Notebook | |
|---|---|---|---|---|
| Cost | Free | $50K+/year | $16K-$40K/year | Free |
| Data source | SaaS-native (Stripe, PostHog, HubSpot, CSV) | Enterprise CRM | SaaS CRM | Telecom CSV only |
| SaaS-native features | Yes | Yes | Yes | No |
| SHAP explanations | Yes | No | No | Rarely |
| LLM intervention plans | Yes (free) | No | No | No |
| Setup time | 15 minutes | 3-6 months | 4-8 weeks | 2 hours, no output |
| Target user | Bootstrapped SaaS, $5K-$500K MRR | Enterprise CS teams | Mid-market | Data scientists only |
Step 1: Clone the repository.
git clone https://github.com/ShreyasDasari/churnguard-ai
cd churnguard-aiStep 2: Open in Google Colab.
Or open churnguard_ai.ipynb in JupyterLab locally.
Step 3: Run Cell 1.1 to install dependencies, then run all cells top-to-bottom. The demo dataset loads automatically -- no configuration required to see output.
| Source | Connection Method | Free Tier | How to Export |
|---|---|---|---|
| Stripe API | stripe Python SDK + secret key |
Free to read (all tiers) | Dashboard > Developers > API Keys |
| PostHog API | HogQL REST API + project API key | 1M events/month free | Project Settings > API Keys |
| HubSpot API | hubspot-api-client + private app token |
250K API calls/day free | Settings > Integrations > Private Apps |
| Universal CSV | pd.read_csv() -- drop files in project folder |
Unlimited | Billing tool > Export > CSV |
Set source="stripe", "posthog", or "hubspot" in Cell 1.6, or provide CSV paths with source="csv".
ChurnGuard's Stripe connector reads two types of Stripe objects -- Subscriptions and Invoices -- and transforms them into the four-file CSV schema ChurnGuard uses internally. The connector is read-only: it never writes to your Stripe account, never triggers a charge, and never modifies a subscription. If you prefer not to use an API key at all, every piece of data the connector reads is also available as a manual CSV export from your Stripe Dashboard under Billing > Subscriptions and Billing > Invoices.
{
"id": "sub_1OqKL2...",
"status": "canceled",
"created": 1704067200,
"canceled_at": 1706745600,
"cancellation_details": {
"feedback": "too_expensive",
"comment": "Found a cheaper alternative"
},
"items": {
"data": [{
"price": {
"unit_amount": 29900,
"recurring": { "interval": "month" }
},
"quantity": 3
}]
},
"customer": {
"id": "cus_9s6XK...",
"email": "john@acmecorp.com",
"created": 1698796800
}
}Note on pricing math:
unit_amountis always stored in cents, so 29900 = $299.00. For seat-based pricing, ChurnGuard multipliesunit_amountbyquantity-- in this example, 3 seats at $299 = $897/month MRR. For annual plans billed upfront, ChurnGuard divides the total by 12 to arrive at a monthly equivalent for consistent MRR comparison.
| Stripe Field | customers.csv Column | How It's Transformed |
|---|---|---|
customer.id |
customer_id |
Used directly as the unique identifier |
customer.created |
signup_date |
Unix timestamp converted to YYYY-MM-DD |
items.data[0].price.unit_amount |
monthly_revenue |
Divided by 100 (cents to dollars). Annual plans divided by 12 |
items.data[0].quantity |
multiplier | Multiplied by unit_amount for seat-based pricing |
status == "canceled" |
is_churned |
True if canceled, False for all other statuses |
canceled_at |
churn_date |
Unix timestamp to date. Null if customer is still active |
cancellation_details.feedback |
churn_reason |
Direct string: too_expensive, missing_features, switched_service, unused |
items.data[0].price.recurring.interval |
contract_type |
"month" to "monthly", "year" to "annual" |
To enable cancellation_details.feedback, turn on Stripe Cancellation Surveys in your Dashboard under Billing > Subscriptions > Cancellation surveys. ChurnGuard reads this field automatically once it is active.
{
"id": "in_1OqKL2...",
"customer": "cus_9s6XK...",
"created": 1704067200,
"amount_paid": 8970,
"status": "open",
"attempt_count": 3,
"paid": false
}Note on failed payments:
attempt_count > 1combined withpaid: falseis how ChurnGuard identifies a failed payment. Stripe retries failed payments automatically on a schedule you configure -- soattempt_count: 3means Stripe has already tried and failed three times without success. By the time ChurnGuard sees this, the customer is already behind on payment and your window to recover them is narrowing. This is treated as a critical churn signal.
| Stripe Field | payment_history.csv Column | How It's Transformed |
|---|---|---|
customer |
customer_id |
Direct |
created |
payment_date |
Unix timestamp converted to YYYY-MM-DD |
amount_paid |
amount |
Divided by 100 (cents to dollars) |
paid == true |
payment_status |
"success" |
paid == false AND attempt_count > 1 |
payment_status |
"failed" |
status == "void" |
payment_status |
"refunded" |
status == "uncollectible" |
payment_status |
"disputed" |
The Universal CSV Schema is deliberately designed to be the lowest common denominator across every billing tool on the market. Paddle, Chargebee, Lemon Squeezy, and even a manually maintained spreadsheet all store the same underlying information -- the column names just differ. Export your data from whichever tool you use, rename the columns to match the schema in the Universal CSV Schema section below, and drop the files into your ChurnGuard project folder. Set source="csv" in Cell 1.6 and provide the file paths -- that is the entire setup.
ChurnGuard does not produce a single "churn score" in isolation. It combines eight signals that each predict cancellation in a different way and with a different lead time. This section explains what each signal is in plain English, when it is in the danger zone, and exactly what to do when it fires.
There are two types of churn signals. Lagging indicators tell you a customer has already churned or is about to cancel this week. By the time you see a lagging signal, your intervention window is essentially closed. Leading indicators warn you 30-90 days before cancellation -- when a conversation, a discount, or a product walkthrough can still change the outcome.
ChurnGuard focuses on leading indicators. The goal is not to detect churn after it happens. The goal is to give your team enough advance warning to prevent it.
| Leading Indicators (30-90 day warning) | Lagging Indicators (too late or barely in time) |
|---|---|
| Usage trend declining | Cancellation request received |
| Days since last active increasing | Failed payment on 3rd attempt |
| Feature adoption stalling | Downgrade already processed |
| Support ticket spike | NPS score of 0 received |
| Seat utilization dropping | Customer stopped responding to emails |
ChurnGuard scores customers primarily on leading indicators. Lagging signals are included as context but should trigger escalation, not standard outreach.
What it is: Is this customer using your product more or less compared to last month? ChurnGuard compares login and activity counts between the current 30-day period and the previous 30-day period.
Why it matters: A customer who was active 15 times a month and is now active 3 times has mentally already decided to leave -- they just haven't canceled yet. This signal predicts cancellation 60-90 days before it happens, which is your entire window to intervene.
Danger zone: Usage dropped more than 30% month-over-month.
What you do: Do not wait for them to contact you. Assign a CS rep to schedule a 20-minute call this week. The agenda: understand what changed, not pitch new features.
What it is: How many days has it been since anyone at this company opened your product?
Why it matters: Silence is the quietest form of churn. Customers who go dark rarely come back without someone reaching out first. Two weeks of inactivity in a product they pay for monthly is abnormal behavior.
Danger zone: More than 14 consecutive days without a single login.
What you do: Send a personal email from a real person (not a no-reply address) within 24 hours of hitting the 14-day mark. Subject line: "Is everything okay with [Product]?" -- not a marketing email.
What it is: Has this customer had a credit card failure, declined payment, or billing error in the last 90 days?
Why it matters: 20-40% of all SaaS churn is involuntary -- the customer never intended to cancel, their card simply failed and nobody followed up. This is the highest return-on-effort signal in the entire model because sending one email with a payment update link recovers the majority of these customers.
Danger zone: Any failed payment. Two failed payments in 90 days is critical.
What you do: Automated email with a payment update link within 24 hours of the first failure. Personal phone call or direct message on the second failure -- do not rely on automation alone at this point.
What it is: How many of your product's core features has this customer actually used since they signed up?
Why it matters: Customers who use only one feature are one competitor with a lower price away from leaving. Customers who have built workflows around 3 or more features have a high switching cost -- it takes real effort to replace something that is woven into how they work.
Danger zone: Customer has used fewer than 2 core features after their first 60 days with your product.
What you do: This is primarily an onboarding failure, not a churn signal. Trigger a personalized email or in-app message showing the specific features they have not tried yet, with a direct link to a 5-minute tutorial. If they are past 90 days, offer a live walkthrough.
What it is: Is this customer paying month-to-month or on an annual contract?
Why it matters: Monthly customers cancel at roughly double the rate of annual customers -- approximately 16% annual churn versus 8.5% for annual plans. This is not a behavioral signal, it is a structural risk factor. A month-to-month customer with any other warning sign is significantly more likely to act on it because there is no cancellation penalty and their next decision point is 30 days away.
Danger zone: Month-to-month contract combined with any other signal above.
What you do: During any retention conversation with a high-risk monthly customer, offer a 15-20% discount for switching to annual. Frame it as saving them money, not locking them in.
What it is: Has this customer opened significantly more support tickets than usual in the last 30 days?
Why it matters: A sudden spike in support tickets almost always means the customer is hitting a wall -- something broke, they cannot figure something out, or they are frustrated with a process. If those tickets take too long to resolve, frustration converts directly to a cancellation decision.
Danger zone: 3 or more tickets in 30 days from a customer who previously averaged fewer than 1 per month, especially if CSAT scores on those tickets are below 3 out of 5.
What you do: Escalate to a senior support engineer immediately. Do not let a frustrated customer wait in a standard queue. Consider a proactive "we noticed you've had a few issues -- can we jump on a call?" message before they ask for it.
What it is: What percentage of the seats or licenses this customer is paying for are actually being used by real people?
Why it matters: A company paying for 20 seats but using only 6 is paying for 14 seats they do not need. At renewal time, they will notice this. Low seat utilization is one of the strongest predictors of a downgrade or full cancellation at the next renewal date.
Danger zone: Below 40% seat utilization with a renewal coming in the next 90 days.
What you do: You have two options and you need to pick the right one. If there is a realistic path to activating more seats (new team members, new departments), help them do it. If there is not, proactively offer a right-sized plan before their renewal -- customers who feel respected during a downgrade conversation almost always stay. Customers who feel surprised by their own renewal invoice often do not.
What it is: Has this customer reduced their plan, removed seats, or lowered their monthly spend in the last 60 days?
Why it matters: A downgrade is a customer voting with their wallet before they vote with their cancellation button. It is almost always a leading signal of full churn -- they are testing whether they can get by with less of your product before they decide to leave entirely.
Danger zone: Any downgrade in the last 60 days, particularly when combined with declining usage.
What you do: Do not ignore a downgrade as a resolved event. Schedule a check-in within two weeks of the downgrade to understand the reason. Was it budget pressure, dissatisfaction, or a change in their business? The answer determines whether this is recoverable and how.
If your product is used every day (project management, team communication, analytics dashboards): Usage trend and days-since-last-active are your most critical signals. A 7-day gap in a daily-use tool is an emergency that warrants immediate outreach, not a weekly digest flag.
If your product is used periodically (quarterly reporting, annual compliance, event-driven tools): Do not panic about low login frequency between events -- that is expected behavior. Focus on payment health, feature adoption, and support ticket velocity instead. A customer who logs in twice a year but has never had a support issue and renews on time is healthy.
If you serve enterprise or large team accounts: Seat utilization and MRR trend are disproportionately important because one enterprise account churning may represent more revenue than 50 SMB accounts combined. Use the revenue_weighted_priority column in ChurnGuard's output -- it automatically surfaces large accounts with moderate risk above small accounts with high risk.
If your average contract value is under $100/month: Payment failures are your single highest-ROI signal to act on. At this price point customers are more likely to let a failed payment slide rather than proactively update their billing information. An automated dunning sequence triggered within 24 hours of a failure can recover 30-50% of these customers before they realize their subscription lapsed.
The percentages next to each signal represent the average predictive weight across thousands of SaaS companies. They are defaults, not mandates. A founder who knows their product deeply may recognize that a specific signal matters much more or less in their context -- a developer tool used once a week by design will behave very differently from a daily CRM. ChurnGuard's model will learn these nuances over time as outcome data is recorded using the record_intervention_outcome() function in Section 8 of the notebook -- the more saved vs. churned outcomes you log, the more the predictions tune to your specific business and customer base.
Place your exports in the project folder using these exact column names.
| Column | Type | Required | Notes |
|---|---|---|---|
customer_id |
string | Yes | Unique account identifier |
signup_date |
YYYY-MM-DD | Yes | Account creation date |
plan_name |
string | Yes | Current subscription plan |
monthly_revenue |
float | Yes | MRR in USD |
is_churned |
boolean | Yes | Target variable (True/False or 1/0) |
contract_type |
string | No | monthly, annual, multi_year |
churn_date |
YYYY-MM-DD | No | Null if active |
company_size |
string | No | 1-10, 11-50, 51-200, 201-1000, 1000+ |
industry |
string | No | Customer vertical |
churn_reason |
string | No | too_expensive, missing_features, switched_service, unused, other |
| Column | Type | Required | Notes |
|---|---|---|---|
customer_id |
string | Yes | FK to customers |
period_start |
YYYY-MM-DD | Yes | Measurement window start |
period_end |
YYYY-MM-DD | Yes | Measurement window end |
total_logins |
integer | No | Login count in period |
active_days |
integer | No | Days with at least 1 session |
features_used_count |
integer | No | Distinct features used |
seats_active |
integer | No | Active users in period |
seats_licensed |
integer | No | Total licensed seats |
days_since_last_active |
integer | No | Inactivity duration at period end |
| Column | Type | Required | Notes |
|---|---|---|---|
customer_id |
string | Yes | FK to customers |
period_start |
YYYY-MM-DD | Yes | Measurement window start |
period_end |
YYYY-MM-DD | Yes | Measurement window end |
tickets_opened |
integer | No | New tickets in period |
avg_resolution_time_hrs |
float | No | Mean resolution time |
csat_score |
float | No | Satisfaction score 1-5 |
nps_score |
integer | No | Net Promoter Score -100 to 100 |
escalations |
integer | No | Escalated ticket count |
| Column | Type | Required | Notes |
|---|---|---|---|
customer_id |
string | Yes | FK to customers |
payment_date |
YYYY-MM-DD | Yes | Transaction date |
amount |
float | Yes | Payment amount in USD |
payment_status |
string | Yes | success, failed, refunded, disputed |
plan_change_type |
string | No | upgrade, downgrade, renewal, new |
- Setup & Data Ingestion -- Install dependencies, configure API keys (optional), and load data from Stripe, PostHog, HubSpot, CSV exports, or the built-in demo dataset.
- Data Validation & EDA -- Validate schema, detect class imbalance, and visualize MRR distributions, tenure curves, and churn reasons.
- Feature Engineering -- Compute 7/30/90-day behavioral windows, login trend velocity, payment failure rates, seat utilization, and support ticket velocity per customer.
- Model Training & Evaluation -- Train LogisticRegression (baseline), XGBoost (primary), and LightGBM (fast alternative) with SMOTEENN resampling; compare by PR-AUC.
- Customer Risk Scoring -- Score all customers with churn probability, assign Critical/High/Medium/Low tiers, and rank by revenue-weighted priority.
- SHAP Explainability -- Compute global feature importance and per-customer SHAP waterfall plots; convert feature values to plain-English churn signals.
- LLM Intervention Plans -- Generate personalized 30-day retention playbooks per at-risk customer using Groq -> Gemini -> OpenRouter -> template fallback chain.
- Persistence, Export & Action -- Save results to SQLite for week-over-week trending, export dated CSV files, sync risk scores to HubSpot contacts.
- Limitations & Re-Run Guide -- Honest assessment of model constraints, next steps, and a monthly re-run checklist.
| Library | Version | Purpose |
|---|---|---|
pandas |
2.2 | Data manipulation and CSV ingestion |
numpy |
1.26 | Numerical operations |
scikit-learn |
1.4 | LogisticRegression, Pipeline, metrics, StandardScaler |
xgboost |
2.1 | Primary churn classifier (target AUC 0.85-0.93) |
lightgbm |
4.3 | Fast alternative classifier for large datasets |
imbalanced-learn |
0.12 | SMOTEENN resampling for class imbalance |
shap |
0.45 | TreeExplainer and per-customer waterfall plots |
plotly |
5.20 | Interactive risk dashboard and evaluation charts |
matplotlib |
3.8 | SHAP summary (beeswarm) plots |
seaborn |
0.13 | Supporting visualizations |
ipywidgets |
8.1 | Interactive threshold slider |
groq |
0.11 | Primary LLM (llama-3.3-70b-versatile, 500K tokens/day free) |
google-generativeai |
0.7 | Fallback LLM (gemini-2.0-flash-lite, 1,000 RPD free) |
stripe |
8.5 | Billing data ingestion (free to read) |
posthog |
3.5 | Product analytics connector |
hubspot-api-client |
10.1 | CRM contacts and deal pipeline |
sqlite3 |
built-in | Persistent storage for scores and outcomes |
requests |
2.31 | OpenRouter HTTP fallback and PostHog HogQL API |
CHURNGUARD AI -- RISK SUMMARY
====================================================
Total customers analyzed: 487
Customers at risk (>=30%): 74 (15%)
Critical risk (>=70%): 23 customers
High risk (50-70%): 31 customers
REVENUE AT RISK
Critical segment MRR: $18,420
High segment MRR: $11,340
Total MRR at risk: $29,760
Estimated ARR at risk: $357,120
PROJECTED RETENTION VALUE
At 20% save rate: $5,952 MRR / $71,424 ARR recoverable
====================================================
CUSTOMER: cust_0137 | RISK: 87.4% | MRR: $999 | TIER: Critical
TOP RISK DRIVERS:
- Has not logged in for 31 days (inactivity signal)
- 3 failed payment(s) in the last 90 days
- Login volume changed -68% vs. prior 30 days
30-DAY RETENTION PLAN:
(1) Immediate Action (within 24 hours):
Call the account owner directly (not email -- this account needs
a personal touch). Lead with: "I noticed some unusual activity on
your account and wanted to check in." Do NOT mention cancellation.
Simultaneously, send a payment update link to the billing contact
-- 3 failed payments is involuntary churn risk.
(2) Week 1 Strategy:
Resolve the payment issue first (it is blocking re-engagement).
Once resolved, offer a 20-minute "account health" call. Prepare
3 specific use cases matching their company size and industry.
Ask what workflows they were trying to accomplish before going dark.
(3) Week 2-3 Follow-up:
Send a "here is what you have been missing" summary -- product
updates and new features released in the past 30 days.
If they are on a monthly plan, offer a 10% discount on annual
commitment to reduce future involuntary churn risk.
(4) Two measurable success metrics:
- Payment successfully processed within 5 business days.
- Customer logs in at least twice within 14 days of call.
Provider: groq
| Segment | Monthly Churn | Annual Churn | Notes |
|---|---|---|---|
| Monthly contracts | ~1.3% | ~16% | Higher price sensitivity |
| Annual contracts | ~0.7% | ~8.5% | Commitment reduces churn |
| SMB-focused ($25-50 ARPU) | ~7.3% | ~88% | Very high turnover |
| Mid-market ($250-500 ARPU) | ~3.5% | ~42% | Standard benchmark |
| Enterprise ($1K+ ARPU) | ~0.5-1% | ~6-12% | Sticky once embedded |
| Involuntary churn share | -- | 20-40% of total | Failed payments |
| 3+ features used in month 1 | -- | 40% higher retention | Feature adoption |
Sources: Baremetrics 2023 SaaS Benchmarks, Mixpanel Product Benchmarks 2024.
How many customers do I need for this to work? At least 100 customers and 30 churn events for meaningful ML predictions. Section 2 validates this automatically and prints a warning if you are below threshold. With fewer customers, the risk scores are still useful as exploratory signals.
My churn rate is under 5% -- is the model still useful? Yes. SMOTEENN handles class imbalance by oversampling churn events during training. The PR-AUC metric is specifically designed for imbalanced datasets. A 3% monthly churn rate on $100K MRR still means $3K/month at risk -- worth predicting.
What if I don't use Stripe?
Use the Universal CSV path (Section 1, source="csv"). Export your billing data to customers.csv and payment_history.csv matching the schema above. The notebook works with any billing tool that can export CSV.
Will my customer data be sent anywhere? Only if you use the LLM intervention feature. Customer risk data (not PII -- just probability scores and SHAP-derived signals) is sent to Groq, Gemini, or OpenRouter to generate intervention plans. If this is a concern, set all API keys to blank and use the template-based fallback, which runs entirely locally.
The LLM intervention feature isn't working -- what do I do?
Leave the API key prompts blank (press Enter). The template-based fallback in Section 7 generates structured retention plans without any external API. Check LLM_CONFIG["provider"] after Cell 7.2 -- it should print template if no keys are configured.
Can I use this for B2C?
ChurnGuard was built for B2B SaaS with identifiable customer accounts. It will work for B2C subscription businesses (streaming, apps) if each user has a customer_id and a monthly_revenue field. The LLM intervention plans are less relevant for B2C at scale -- use the risk scores to trigger automated email sequences instead.
- Minimum data requirements: Needs 100+ customers and 30+ churn events. Smaller datasets produce unreliable predictions.
- Cold start problem: Customers in their first 14 days have no behavioral history and cannot be reliably scored. Use onboarding playbooks for new customers.
- Correlation, not causation: Declining usage predicts churn but does not prove it. Treat flags as conversation starters, not confirmed cancellations.
- Free LLM tier instability: Groq, Gemini, and OpenRouter have changed free tiers without notice. The template fallback always works with no external dependencies.
- Point-in-time analysis: Re-run monthly or weekly. Scores go stale as customer behavior changes.
- Fork the repository on GitHub.
- Create a feature branch:
git checkout -b feature/paddle-connector - Follow the connector pattern established in
cells_section1.pyfor new data source integrations. - Ensure all functions have type hints, docstrings (with Parameters and Returns), and single responsibility (max 40 lines).
- Open a pull request describing what your connector does and which billing/analytics tool it targets.
Bug reports and feature requests are welcome via GitHub Issues.
MIT License
Copyright (c) 2026 Shreyas
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- Groq for providing a generous free tier for the LLaMA 3.3 70B model that powers the intervention plan generator.
- PostHog for open-source product analytics and a well-documented HogQL API.
- scikit-learn and XGBoost communities for the ML foundations this tool is built on.
- The IBM Telco Churn dataset, which was used only in early development exploration to validate the feature engineering pipeline before the SaaS-native demo data generator was built.