DenchClaw + Stripe: Track Revenue in Your CRM
Connect Stripe revenue data to DenchClaw — import customers and subscriptions into DuckDB, track MRR, and link Stripe status to CRM deal stages.
DenchClaw + Stripe: Track Revenue in Your CRM
Your CRM has leads and deals. Your Stripe dashboard has customers and revenue. These two datasets live in separate tools, so the answer to "which of my closed deals are actually paying?" requires logging into Stripe separately. DenchClaw connects these by pulling Stripe data into DuckDB, linking Stripe customers to CRM contacts, and letting you build revenue analytics on top of your local database.
Here's how to set it up.
Accessing Stripe via the Browser Agent#
DenchClaw's browser agent copies your Chrome session, which means if you're logged into Stripe's dashboard in Chrome, the browser agent has access too. No Stripe API key setup, no restricted key scopes to configure.
The browser agent can navigate Stripe's dashboard to:
- Read customer lists and individual customer records
- View subscription status and billing details
- Access revenue metrics (MRR, ARR, churn)
- Read invoice history
This works for team members who have Stripe dashboard access through their account — the browser agent inherits whatever access level your Stripe user has.
Alternative: Stripe API key (for automation)#
For scheduled syncs that run without interactive browser sessions, you can configure a Stripe restricted API key:
npx denchclaw config set stripe.api_key sk_live_xxxxCreate a restricted key in Stripe with read-only access to:
- Customers
- Subscriptions
- Invoices
- Payment intents
This is optional — the browser agent approach works for manual and scheduled syncs. The API key approach is better for high-frequency automated syncs.
Importing Customer and Subscription Data to DuckDB#
Initial import: all Stripe customers#
"Import all customers from my Stripe account into DenchClaw"
DenchClaw pulls each customer's:
- Name and email
- Created date
- Subscription status (active, trialing, past_due, canceled)
- Current plan/product name
- Subscription amount (MRR contribution)
- Next billing date
- Customer metadata fields
All of this lands in a stripe_customers table in DuckDB alongside your existing CRM data.
-- See what was imported
SELECT
name,
email,
subscription_status,
plan_name,
mrr_amount,
subscription_start_date
FROM stripe_customers
ORDER BY mrr_amount DESC
LIMIT 20;Incremental syncs#
After the initial import, set up incremental updates:
"Sync Stripe customer data every night at midnight"
DenchClaw fetches only records changed since the last sync, updating the DuckDB table without a full re-import.
You can also sync on demand:
"Sync Stripe now — I just had a new signup"
Linking Stripe Customers to CRM Contacts#
Stripe customers and CRM contacts are matched by email address. When an email appears in both DuckDB tables, DenchClaw creates a link between them.
-- Find CRM contacts with matching Stripe customers
SELECT
c.name,
c.company,
c.deal_stage,
sc.subscription_status,
sc.mrr_amount,
sc.plan_name
FROM v_contacts c
JOIN stripe_customers sc ON sc.email = c.email
WHERE sc.subscription_status = 'active'
ORDER BY sc.mrr_amount DESC;For contacts that exist in your CRM but not in Stripe yet:
-- Closed-won deals with no Stripe customer
SELECT
c.name,
c.company,
c.deal_value,
c.close_date
FROM v_contacts c
LEFT JOIN stripe_customers sc ON sc.email = c.email
WHERE c.deal_stage = 'Closed Won'
AND sc.email IS NULL
ORDER BY c.close_date DESC;This surface contacts where you've marked the deal as won but they haven't been billed yet — useful for catching deals that didn't get fully processed.
Manual link when emails don't match#
Sometimes the CRM contact email and Stripe customer email differ (different addresses for billing vs. contact). Link them manually:
"Link Sarah Chen's CRM contact to Stripe customer ID cus_abc123"
DenchClaw stores the Stripe customer ID on the contact record and uses that for future matching.
Revenue Analytics via DuckDB Queries#
Once Stripe data is in DuckDB alongside your CRM, you can run analyses that neither tool supports on its own.
Current MRR by pipeline stage:
SELECT
COALESCE(c.deal_stage, 'No CRM Record') AS stage,
COUNT(*) AS customers,
SUM(sc.mrr_amount) AS total_mrr,
AVG(sc.mrr_amount) AS avg_mrr
FROM stripe_customers sc
LEFT JOIN v_contacts c ON c.email = sc.email
WHERE sc.subscription_status = 'active'
GROUP BY 1
ORDER BY total_mrr DESC;Monthly new MRR (new customers each month):
SELECT
DATE_TRUNC('month', subscription_start_date) AS month,
COUNT(*) AS new_customers,
SUM(mrr_amount) AS new_mrr
FROM stripe_customers
WHERE subscription_status IN ('active', 'trialing')
GROUP BY 1
ORDER BY 1 DESC
LIMIT 12;Churn analysis — canceled customers and their CRM history:
SELECT
sc.name,
sc.email,
sc.subscription_status,
sc.canceled_at,
sc.mrr_amount AS churned_mrr,
c.deal_stage AS last_crm_stage
FROM stripe_customers sc
LEFT JOIN v_contacts c ON c.email = sc.email
WHERE sc.subscription_status = 'canceled'
AND sc.canceled_at > NOW() - INTERVAL '90 days'
ORDER BY sc.canceled_at DESC;Revenue by lead source:
SELECT
c.lead_source,
COUNT(DISTINCT sc.id) AS paying_customers,
SUM(sc.mrr_amount) AS mrr
FROM v_contacts c
JOIN stripe_customers sc ON sc.email = c.email
WHERE sc.subscription_status = 'active'
GROUP BY c.lead_source
ORDER BY mrr DESC;Expansion revenue — customers who upgraded:
SELECT
sc.name,
sc.email,
sc.plan_name,
sc.mrr_amount AS current_mrr,
sh.previous_mrr,
sc.mrr_amount - sh.previous_mrr AS expansion_mrr
FROM stripe_customers sc
JOIN stripe_subscription_history sh ON sh.customer_id = sc.stripe_id
WHERE sc.mrr_amount > sh.previous_mrr
AND sh.change_date > NOW() - INTERVAL '30 days'
ORDER BY expansion_mrr DESC;Setting Deal Stages Based on Stripe Subscription Status#
One of the most powerful setups is keeping your CRM pipeline in sync with Stripe's subscription status automatically.
"When a Stripe subscription becomes active, update the contact's deal stage to 'Closed Won'"
"When a Stripe subscription is canceled, update the contact's stage to 'Churned'"
"When a subscription goes past_due, add a task to contact the customer"
DenchClaw monitors Stripe subscription status changes (via the nightly sync or via webhook) and applies the corresponding CRM updates.
Stripe webhook setup (for real-time updates)#
For immediate updates instead of nightly syncs:
- In Stripe Dashboard → Developers → Webhooks, add an endpoint
- Set the endpoint URL to your DenchClaw webhook URL
- Subscribe to events:
customer.subscription.updated,customer.subscription.deleted,invoice.payment_failed
npx denchclaw webhook register stripe \
--events customer.subscription.updated,customer.subscription.deleted,invoice.payment_failedDenchClaw generates a webhook URL and registers a handler. When Stripe fires an event, DenchClaw processes it and updates the DuckDB record in real time.
Dashboard App: MRR/ARR From DuckDB#
DenchClaw can generate a revenue dashboard app that reads directly from DuckDB — no Stripe dashboard needed.
"Build a revenue dashboard app showing MRR, ARR, churn rate, and new customers this month"
DenchClaw creates a .dench.app web application with:
- Current MRR and ARR metrics
- Month-over-month growth chart
- New vs. churned customers this month
- Subscription status breakdown
- Top 10 customers by MRR
The app reads from DuckDB in real time. You can share it with your team or embed it in your internal tooling.
-- Key metrics query for the dashboard
SELECT
SUM(CASE WHEN subscription_status = 'active' THEN mrr_amount ELSE 0 END) AS mrr,
SUM(CASE WHEN subscription_status = 'active' THEN mrr_amount ELSE 0 END) * 12 AS arr,
COUNT(CASE WHEN subscription_status = 'active' THEN 1 END) AS active_customers,
COUNT(CASE WHEN subscription_status = 'trialing' THEN 1 END) AS trialing,
COUNT(CASE WHEN subscription_status = 'canceled'
AND canceled_at > DATE_TRUNC('month', NOW()) THEN 1 END) AS churned_this_month
FROM stripe_customers;Frequently Asked Questions#
Does DenchClaw store payment card data?
No. DenchClaw only reads customer metadata, subscription status, and billing amounts from Stripe. Payment card data (PAN, CVV) is never exposed via Stripe's dashboard or API to non-PCI-compliant systems. DenchClaw stores what Stripe shows: subscription plan, amount, status — not card numbers.
Can I use this with Stripe's test mode?
Yes. The browser agent doesn't distinguish between test and live mode — it navigates whatever you're logged into. If you want to test the integration, log into Stripe's test mode in Chrome, then tell DenchClaw to sync. For API key setup, use your test key (sk_test_...).
What if a customer has multiple subscriptions?
DenchClaw imports each subscription as a separate record linked to the same customer. Your MRR aggregation will sum all active subscriptions per customer. The stripe_customers table has a separate row per subscription, joined on customer_id.
Can I trigger Stripe actions from DenchClaw?
Read operations work via browser agent and API key. Write operations (creating customers, updating subscriptions) require a Stripe API key with write permissions and should be done carefully. DenchClaw can trigger these, but will ask for confirmation before any Stripe write operation.
How does DenchClaw handle Stripe Connect (platform accounts)?
DenchClaw syncs the data visible in your dashboard. For Stripe Connect platforms, you can view connected account data if you have access in the dashboard. Platform-level revenue aggregation across connected accounts is possible but requires configuring access to each connected account separately.
Ready to try DenchClaw? Install in one command: npx denchclaw. Full setup guide →
