Every founder I talk to has the same story: "We didn't notice churn spiked until Friday's board prep." The fix is simple — automated Slack alerts when your business metrics cross a threshold. Here's how to set it up in under 10 minutes.
The core idea is this: define a condition (MRR dropped more than 3% week-over-week), pick a channel (#revenue-alerts), and let a system check that condition on a schedule. When it fires, you get a message with context — what changed, by how much, and since when.
This isn't infrastructure monitoring. Datadog and PagerDuty are built for "is the server down?" alerts. What we're talking about is business metric monitoring: revenue, churn, signups, failed payments, CAC payback — the numbers that determine whether your company is healthy.
What to alert on
Not everything deserves an alert. The goal is signal, not noise. Here are the conditions that actually matter for most SaaS businesses:
Revenue alerts:
- MRR drops more than 3% week-over-week
- Net revenue retention falls below 100% for a rolling 30-day window
- Failed payments exceed 5 in a single hour
- A single customer's subscription value drops by more than $500
Growth alerts:
- Daily signups fall below the 7-day rolling average by more than 30%
- Trial-to-paid conversion rate drops below 5% for a 7-day cohort
- CAC payback period exceeds 12 months for any acquisition channel
Operational alerts:
- NPS or CSAT score drops below 30
- Support ticket volume spikes above 2x the daily average
- A key customer hasn't logged in for 7+ days
The common thread: these are conditions where early detection changes the outcome. A 3% MRR drop caught on Monday gives you the week to intervene. Caught on Friday, it's already compounded.
Three approaches to Slack metric alerts
Approach 1: Custom Python script
The most common first attempt — and honestly, it works fine for one or two alerts. Here's a complete working example that checks for failed payments and posts to Slack:
# check_failed_payments.py
import os
import psycopg2
import requests
from datetime import datetime
SLACK_WEBHOOK = os.environ["SLACK_WEBHOOK_URL"]
DB_URL = os.environ["DATABASE_URL"]
def check_and_alert():
conn = psycopg2.connect(DB_URL)
cursor = conn.cursor()
cursor.execute("""
SELECT COUNT(*) FROM payments
WHERE status = 'failed'
AND created_at > now() - interval '1 hour'
""")
failed_count = cursor.fetchone()[0]
cursor.execute("""
SELECT AVG(hourly_failures) FROM (
SELECT COUNT(*) as hourly_failures
FROM payments
WHERE status = 'failed'
AND created_at > now() - interval '7 days'
GROUP BY date_trunc('hour', created_at)
) sub
""")
avg_hourly = cursor.fetchone()[0] or 0
if failed_count > max(5, avg_hourly * 2):
requests.post(SLACK_WEBHOOK, json={
"text": (
f":warning: *Failed payments spike*\n"
f"{failed_count} failed payments in the last hour "
f"(avg: {avg_hourly:.1f}/hr over 7 days)\n"
f"Check: https://dashboard.stripe.com/payments?status=failed"
)
})
conn.close()
if __name__ == "__main__":
check_and_alert()Deploy this on a cron job (0 * * * * for hourly) using your server, a Lambda function, or a GitHub Action. Total cost: $0.
The problem: This works for 1-2 alerts. By the time you have 5+, you're maintaining a collection of scripts with no observability, no history of when they fired, and no way for non-engineers to modify thresholds. The scripts are also silent when they fail — if the database connection times out at 3am, nobody knows the alert system itself is broken.
Approach 2: Zapier + SQL (limited)
Zapier can connect to databases and send Slack messages, but the SQL support is primitive. You can't do rolling averages, window functions, or multi-step logic. It works for simple threshold checks like "is this number above X?" but falls apart for anything resembling real business logic.
The bigger issue: Zapier charges per task, and a check that runs every 15 minutes across 5 conditions burns through your task quota fast. At $50-100/month for the SQL add-ons, you're paying enterprise prices for a tool that can't do LAG().
Approach 3: Fastero triggers
This is what we built Fastero to do. Connect your database (or Stripe directly), write a condition in plain English or SQL, pick a Slack channel, and set a schedule.
Step 1: Connect your data source. In the Fastero app, add a connection — Stripe for billing data, Postgres/BigQuery for your product database, or both. Read-only access, encrypted in transit.
Step 2: Create a trigger. Describe your condition. You can use plain English ("alert me if MRR drops more than 5% week-over-week") and Fastero generates the SQL, or write the SQL directly if you prefer precision.
Step 3: Set the schedule. How often should this check run? Every hour for critical metrics (failed payments), daily for trend-based metrics (MRR, churn rate), weekly for slow-moving indicators (NRR, LTV).
Step 4: Pick your Slack channel. Connect Slack via OAuth and choose the channel. Fastero posts a formatted message with the metric value, the threshold it crossed, a comparison to the previous period, and a link to drill deeper.
Step 5: Add context to the alert. The difference between a useful alert and an annoying one is context. Fastero includes what changed (MRR dropped 4.2%), since when (compared to last week), why it might have happened (3 customers on the Pro plan churned), and what to look at next (link to the affected customers).
The DIY version (if you want full control)
Here's a more complete Python script that handles MRR week-over-week comparison with proper context in the Slack message:
# check_mrr_drop.py
import os
import psycopg2
import requests
SLACK_WEBHOOK = os.environ["SLACK_WEBHOOK_URL"]
THRESHOLD_PCT = 3.0 # Alert if MRR drops more than 3%
def check_mrr():
conn = psycopg2.connect(os.environ["DATABASE_URL"])
cursor = conn.cursor()
cursor.execute("""
WITH weekly_mrr AS (
SELECT
date_trunc('week', period_start) AS week,
SUM(amount) / 100.0 AS mrr
FROM subscriptions
WHERE status = 'active'
GROUP BY 1
ORDER BY 1 DESC
LIMIT 2
)
SELECT
curr.mrr AS current_mrr,
prev.mrr AS previous_mrr,
((curr.mrr - prev.mrr) / prev.mrr * 100) AS pct_change
FROM weekly_mrr curr
CROSS JOIN (SELECT mrr FROM weekly_mrr OFFSET 1 LIMIT 1) prev
LIMIT 1
""")
row = cursor.fetchone()
if row and row[2] and row[2] < -THRESHOLD_PCT:
current, previous, pct = row
requests.post(SLACK_WEBHOOK, json={
"text": (
f":chart_with_downwards_trend: *MRR dropped {abs(pct):.1f}% week-over-week*\n"
f"Current: ${current:,.0f} | Previous: ${previous:,.0f}\n"
f"Delta: -${abs(current - previous):,.0f}\n"
f"Threshold: {THRESHOLD_PCT}%"
)
})
conn.close()
if __name__ == "__main__":
check_mrr()This is ~25 lines of real logic. If you're comfortable deploying cron jobs and don't need a UI, this works. The tradeoff is maintenance burden as you scale past a handful of alerts.
What to avoid
Alert fatigue. If your #alerts channel posts 20 messages a day, people stop reading it. Be aggressive about thresholds — only alert on conditions where someone needs to take action. "MRR changed" is noise. "MRR dropped 5% and here are the customers who churned" is signal.
Alerting on noise. Daily metrics fluctuate. A single bad day doesn't mean the business is broken. Use rolling averages (7-day, 14-day) instead of point-in-time comparisons. Alert on "churn rate above 3% for 3 consecutive days" rather than "churn rate above 3% today."
Missing context in the message. An alert that says "MRR below threshold" is useless. Include: the current value, the threshold, the comparison period, and ideally a hypothesis about what caused it. The person reading the alert at 8am shouldn't need to open three tools to understand what happened.
Not monitoring the monitor. If your alert script crashes silently, you have zero alerting and don't know it. Whatever system you use, make sure it has its own health check — a heartbeat message that confirms "the alert system ran successfully at 9am, no conditions triggered."
Which approach to pick
If you have 1-2 alerts and an engineer who likes maintaining scripts: the Python DIY approach is fast and free.
If you need 5+ alerts, want non-engineers to modify thresholds, and don't want to maintain infrastructure: Fastero triggers handle the scheduling, monitoring, and Slack delivery — with AI that generates the SQL and explains what changed.
Either way, the important thing is that the alerts exist. Most SaaS companies discover revenue problems days or weeks late — not because the data wasn't there, but because nobody was watching it automatically. Fix that, and you buy yourself time to respond.
Related reading:

