Skip to main content
Independent community resource — not affiliated with the official OpenClaw project. Learn more
Part 1 of 5OpenClaw for SaaS

MRR & Revenue Monitoring with OpenClaw

Use cases at a glance

Revenue monitoring for SaaS is not just about knowing your MRR number — it's about knowing why it changed overnight. These agents pull from Stripe, compute the standard SaaS MRR movement components, and surface the answer before you open your laptop.

📊 Daily MRR Snapshot

Total active MRR at end of day, compared to yesterday and the same day last month. Delivered every morning.

📈 MRR Movement Breakdown

New MRR from signups, expansion MRR from upgrades, contraction MRR from downgrades, and churned MRR from cancellations — all in one view.

🚨 Overnight Drop Alert

Immediate alert if MRR drops more than your configured threshold overnight — before your morning standup.

📅 Weekly ARR Summary

Weekly ARR snapshot, month-to-date MRR movement, revenue vs target tracking, and 30-day cohort retention revenue.

🏆 Top Accounts Report

Top 10 accounts by MRR, recently churned accounts with their MRR value, and newly upgraded accounts this week.

Stripe restricted key setup

Always use a restricted key — never your secret key — for read-only monitoring. Create one in 4 steps:

  1. Go to Stripe Dashboard → Developers → API keys → Create restricted key
  2. Name it something identifiable: openclaw-monitoring-read
  3. Grant Read access to: Customers, Subscriptions, Invoices, Payment Intents, Charges, Payouts. Grant No access to everything else.
  4. Add to your secrets.env:
    STRIPE_RESTRICTED_KEY=rk_live_xxxxxxxxxxxx STRIPE_ACCOUNT_CURRENCY=usd # your base currency for MRR calculations
⚠️ Never use your Stripe secret key (sk_live_...) for monitoring. A restricted key with read-only permissions cannot initiate charges, process refunds, or modify subscriptions — even if OpenClaw were ever misconfigured.

Daily MRR snapshot agent

This agent queries all active subscriptions, normalises billing amounts to monthly figures, and stores a daily snapshot. It handles annual plans (divides by 12), semi-annual plans (divides by 6), and weekly plans (multiplies by 4.33). Metered/usage-based subscriptions are flagged separately.

agents: mrr-snapshot: description: "Compute and report daily MRR from active Stripe subscriptions" tools: - stripe-api config: stripe_key: "${STRIPE_RESTRICTED_KEY}" base_currency: "${STRIPE_ACCOUNT_CURRENCY}" subscription_statuses: - active - trialing # include trialing if you count trial MRR exclude_statuses: - canceled - incomplete - incomplete_expired - past_due # optionally exclude past_due from MRR normalize_to: monthly # normalise all billing periods to monthly metered_handling: flag # "flag" reports them separately; "exclude" omits them store_snapshot: true # store today's value for tomorrow's delta calculation output: format: markdown include_top_accounts: 10 include_plan_breakdown: true

MRR movement breakdown

The movement breakdown compares today's subscription state against yesterday's stored snapshot. It classifies each subscription change into one of four categories:

CategoryDefinitionStripe event
New MRRSubscription created and now active for the first timecustomer.subscription.created
Expansion MRRExisting subscription upgraded to a higher plancustomer.subscription.updated (amount ↑)
Contraction MRRExisting subscription downgraded to a lower plancustomer.subscription.updated (amount ↓)
Churned MRRSubscription cancelled (voluntary or involuntary)customer.subscription.deleted

Add the movement breakdown to your snapshot agent config:

agents: mrr-movement: description: "Compute MRR movement breakdown vs yesterday's snapshot" tools: - stripe-api config: stripe_key: "${STRIPE_RESTRICTED_KEY}" lookback_hours: 24 movement_categories: - new_mrr - expansion_mrr - contraction_mrr - churned_mrr - reactivation_mrr # cancelled subscription reactivated include_account_names: true # list affected customer names per category currency: "${STRIPE_ACCOUNT_CURRENCY}" output: format: markdown

Overnight drop alert

This is the agent you want running even on weekends. It checks your current MRR against the stored snapshot and fires an alert if the drop exceeds your threshold — useful for catching a large enterprise cancellation before your support team even opens Slack.

agents: mrr-drop-alert: description: "Alert if MRR drops more than threshold overnight" tools: - stripe-api config: stripe_key: "${STRIPE_RESTRICTED_KEY}" currency: "${STRIPE_ACCOUNT_CURRENCY}" alert_threshold: type: percentage # "percentage" or "absolute" value: 3 # alert if MRR drops more than 3% also_alert_on: single_cancellation_above: 500 # alert if any single account cancels > $500 MRR output: format: markdown only_on_trigger: true # only generate a report if threshold is exceeded heartbeats: mrr-drop-check: schedule: "0 * * * *" # check every hour agent: mrr-drop-alert
✅ Recommended threshold: Start at 3% for businesses under $50k MRR, 1.5% for businesses above. Pair with a single_cancellation_above value set to roughly 1% of your MRR — that way a large single cancellation always fires even if the percentage threshold isn't crossed yet.

Weekly ARR & cohort summary

Runs every Monday morning. Covers the full week's MRR movement, ARR (MRR × 12), month-to-date net new MRR, revenue vs your target, and a 30-day cohort retention breakdown showing how much revenue from last month's new customers is still active.

agents: weekly-arr-summary: description: "Weekly ARR snapshot, MTD MRR movement, and 30-day cohort retention" tools: - stripe-api config: stripe_key: "${STRIPE_RESTRICTED_KEY}" currency: "${STRIPE_ACCOUNT_CURRENCY}" sections: - current_arr # MRR × 12 - mtd_net_new_mrr # month-to-date net new MRR - weekly_movement_breakdown # new/expansion/contraction/churn for the week - mrr_vs_target # requires target value below - cohort_30d_retention # revenue from last month's new customers still active - top_10_accounts_by_mrr - churned_accounts_this_week mrr_target_monthly: 25000 # your monthly MRR target in base currency units heartbeats: weekly-revenue-report: schedule: "0 8 * * 1" # Mondays at 8am agent: weekly-arr-summary

HEARTBEAT templates

heartbeats: # Daily MRR snapshot — every morning at 7am daily-mrr: schedule: "0 7 * * *" agent: mrr-snapshot # MRR movement breakdown — every morning at 7:05am (after snapshot runs) daily-mrr-movement: schedule: "5 7 * * *" agent: mrr-movement # Overnight drop check — hourly mrr-drop-watch: schedule: "0 * * * *" agent: mrr-drop-alert # Weekly ARR summary — Mondays at 8am weekly-revenue: schedule: "0 8 * * 1" agent: weekly-arr-summary

Sample report output

## Daily MRR Report — Thursday, March 26, 2026 **Total MRR:** $47,320 (+$640 vs yesterday) **ARR run rate:** $567,840 ### 📊 MRR Movement (last 24h) | Category | Amount | Accounts | |---|---|---| | ✨ New MRR | +$1,190 | 4 new customers | | ⬆️ Expansion MRR | +$380 | 2 upgrades | | ⬇️ Contraction MRR | -$240 | 1 downgrade | | ❌ Churned MRR | -$690 | 2 cancellations | | **Net new MRR** | **+$640** | | ### 🏆 Top 10 Accounts by MRR 1. Acme Corp — $2,400/mo (Enterprise) 2. Brightfield Inc — $1,800/mo (Enterprise) 3. ... (8 more) ### ❌ Churned Today - Sundown LLC — $490/mo (Growth plan, 8 months) - Temp Agency Co — $200/mo (Starter plan, 2 months)

FAQ

How does OpenClaw calculate MRR from Stripe?

It queries the Stripe Subscriptions API for all active subscriptions, normalises each to a monthly figure (annual plans ÷ 12, weekly plans × 4.33), and sums them. It then compares against yesterday's snapshot to compute the movement breakdown. The result matches standard SaaS MRR definitions used by tools like Baremetrics or ChartMogul.

Is it as accurate as a dedicated MRR tool?

For most setups yes. Edge cases include metered/usage-based subscriptions (flagged separately), multi-currency (uses Stripe's embedded exchange rates), and complex discount structures. Use it as a daily health signal rather than an audited source of truth for investor reporting.

How should I set the overnight drop threshold?

Start at 3-5% for businesses under $50k MRR, and 1-2% above that. Pair it with a single_cancellation_above value at roughly 1% of your MRR so a large single cancellation always fires even if the percentage threshold isn't met.