Customer success teams spend a lot of time looking at lagging indicators: NPS scores, support ticket volume, renewal rates. These matter, but by the time they show up in your dashboard, the problem is already weeks old.
The signals that actually predict churn product abandonment, drop-offs in key workflows, declining session frequency live in your database. Right now. Your events table knows which customers stopped using a feature three weeks before they cancelled. Your sessions table knows who's down to one login a week from five. Your invoices table knows which accounts have been on a monthly plan for 18 months and are prime expansion candidates.
This guide walks through the specific metrics worth tracking, the SQL to pull them, and how to make this a live process rather than a manual one.
Why CRM Data Alone Isn't Enough
Most CS teams run their operations out of Salesforce, HubSpot, or a similar CRM. These tools are excellent for managing relationships and tracking communication history but they only know what you tell them. They don't know what your customers are actually doing inside your product.
Your database, on the other hand, captures everything: every login, every feature click, every API call, every export. The gap between what the CRM says ("Account is healthy, last call was positive") and what the database says ("User hasn't logged in for 23 days") is where churn surprises come from.
Bridging that gap means pulling product usage data from your database and turning it into actionable CS metrics without requiring your engineers to build a custom analytics pipeline.
The 6 Customer Success Metrics That Matter Most
1. Daily/Weekly Active Users Per Account
A simple count of distinct users who performed any action in the last 7 or 30 days. This is your baseline health indicator.
SELECT
u.account_id,
a.name AS account_name,
COUNT(DISTINCT u.id) AS total_users,
COUNT(DISTINCT CASE WHEN e.created_at >= NOW() - INTERVAL '7 days' THEN e.user_id END) AS active_last_7d,
COUNT(DISTINCT CASE WHEN e.created_at >= NOW() - INTERVAL '30 days' THEN e.user_id END) AS active_last_30d
FROM accounts a
JOIN users u ON u.account_id = a.id
LEFT JOIN events e ON e.user_id = u.id
GROUP BY u.account_id, a.name
ORDER BY active_last_7d DESC;The key metric here is the ratio: if an account has 20 users but only 3 were active last week, that's a red flag worth a CS touchpoint.
2. Feature Adoption Rate
Which of your core features is each account using? Low adoption on key features is a reliable predictor of churn and also flags expansion opportunities (accounts not using a feature you're paid for).
SELECT
a.id AS account_id,
a.name,
COUNT(DISTINCT CASE WHEN e.event_type = 'dashboard_viewed' THEN e.user_id END) AS users_using_dashboards,
COUNT(DISTINCT CASE WHEN e.event_type = 'report_exported' THEN e.user_id END) AS users_using_exports,
COUNT(DISTINCT CASE WHEN e.event_type = 'workflow_triggered' THEN e.user_id END) AS users_using_workflows,
COUNT(DISTINCT u.id) AS total_users
FROM accounts a
JOIN users u ON u.account_id = a.id
LEFT JOIN events e ON e.user_id = u.id
AND e.created_at >= NOW() - INTERVAL '30 days'
GROUP BY a.id, a.name;An account with zero rows in users_using_workflows when workflows is a core part of your value proposition is an account at risk and an account worth calling.
3. Login Frequency Trend
Not just whether a user is active, but whether their activity is increasing, stable, or declining. A customer who logged in 20 times in January and 8 times in March is trending toward churn even if they're technically "active."
SELECT
u.account_id,
a.name,
COUNT(CASE WHEN l.created_at BETWEEN DATE_TRUNC('month', NOW() - INTERVAL '2 months')
AND DATE_TRUNC('month', NOW() - INTERVAL '1 month') THEN 1 END) AS logins_two_months_ago,
COUNT(CASE WHEN l.created_at BETWEEN DATE_TRUNC('month', NOW() - INTERVAL '1 month')
AND DATE_TRUNC('month', NOW()) THEN 1 END) AS logins_last_month,
COUNT(CASE WHEN l.created_at >= DATE_TRUNC('month', NOW()) THEN 1 END) AS logins_this_month
FROM accounts a
JOIN users u ON u.account_id = a.id
LEFT JOIN logins l ON l.user_id = u.id
GROUP BY u.account_id, a.name
HAVING COUNT(CASE WHEN l.created_at >= DATE_TRUNC('month', NOW() - INTERVAL '2 months') THEN 1 END) > 0
ORDER BY logins_this_month ASC;Sorting by logins_this_month ascending surfaces accounts where engagement is lowest useful for prioritizing CS outreach.
4. Days Since Last Activity
A blunt but useful metric: how many days since anyone in this account did anything?
SELECT
a.id,
a.name,
a.plan_type,
MAX(e.created_at) AS last_activity_date,
DATEDIFF(NOW(), MAX(e.created_at)) AS days_since_last_activity
FROM accounts a
JOIN users u ON u.account_id = a.id
LEFT JOIN events e ON e.user_id = u.id
GROUP BY a.id, a.name, a.plan_type
HAVING DATEDIFF(NOW(), MAX(e.created_at)) > 14
ORDER BY days_since_last_activity DESC;Any account inactive for 14+ days that's on a paid plan should be on your CS radar. Accounts inactive for 30+ days on an annual plan are renewal risks.
5. Onboarding Completion Rate
For new accounts (joined in the last 60 days), what percentage have completed the key onboarding milestones? Incomplete onboarding is the single biggest driver of early churn.
SELECT
a.id,
a.name,
a.created_at AS account_created,
MAX(CASE WHEN e.event_type = 'first_query_run' THEN 1 ELSE 0 END) AS completed_first_query,
MAX(CASE WHEN e.event_type = 'dashboard_created' THEN 1 ELSE 0 END) AS created_dashboard,
MAX(CASE WHEN e.event_type = 'team_member_invited' THEN 1 ELSE 0 END) AS invited_team_member,
MAX(CASE WHEN e.event_type = 'integration_connected' THEN 1 ELSE 0 END) AS connected_integration
FROM accounts a
JOIN users u ON u.account_id = a.id
LEFT JOIN events e ON e.user_id = u.id
WHERE a.created_at >= NOW() - INTERVAL '60 days'
GROUP BY a.id, a.name, a.created_at
ORDER BY a.created_at DESC;This immediately tells you which new accounts are stuck and at what step. A CS team that reviews this weekly can intervene before the customer quietly disengages.
6. Expansion Signals
Not all database metrics are about churn prevention. Some flag upsell opportunities. Which accounts are hitting usage limits, inviting more users than their plan allows, or consistently using features that are only available on higher tiers?
SELECT
a.id,
a.name,
a.plan_type,
COUNT(DISTINCT u.id) AS current_user_count,
p.user_limit,
COUNT(DISTINCT u.id) * 100.0 / p.user_limit AS pct_of_limit,
COUNT(DISTINCT e.id) AS events_last_30d
FROM accounts a
JOIN plans p ON p.id = a.plan_id
JOIN users u ON u.account_id = a.id
LEFT JOIN events e ON e.user_id = u.id
AND e.created_at >= NOW() - INTERVAL '30 days'
GROUP BY a.id, a.name, a.plan_type, p.user_limit
HAVING pct_of_limit > 80
ORDER BY pct_of_limit DESC;Accounts at 80%+ of their user limit are expansion candidates. CS can reach out proactively with upgrade options rather than waiting for the customer to hit a wall.
Making This Continuous, Not Manual
Running these queries once is useful. Running them every Monday is better. But the real value comes when this data flows to your CS team without anyone having to think about it.
There are a few ways to do this:
Option 1: Schedule queries to export to Google Sheets
Most database tools let you schedule a query and export results to a spreadsheet. Set up a weekly export and share it with your CS team. Simple, no engineering required, but it's still a pull model someone has to look at the sheet.
Option 2: Build dashboards that refresh automatically
A live dashboard showing health scores per account, segmented by plan type and days since last activity, gives your CS team a real-time view without any manual pulling. Tools like AI for Database let you build dashboards from natural-language queries that refresh on a schedule so your account health board is always current.
Option 3: Set up automated alerts for key thresholds
The most proactive approach: define the conditions that matter (account inactive for 14 days, onboarding milestone not completed after 7 days, usage below threshold) and trigger a Slack message or email automatically when any account hits them.
With AI for Database's action workflows, you can set conditions like "when an account's last activity date is more than 14 days ago and their renewal is within 60 days" and automatically send a Slack notification to the account's CS manager. No stored procedures, no DBA involvement, no engineering ticket.
Building a Simple Customer Health Score
Once you have these metrics, the natural next step is combining them into a single health score per account. This doesn't need to be sophisticated a weighted average of a few key signals is usually enough to drive prioritization.
Here's a simple approach:
WITH health_signals AS (
SELECT
a.id,
a.name,
a.plan_type,
-- Activity score (0-40 points)
CASE
WHEN MAX(e.created_at) >= NOW() - INTERVAL '3 days' THEN 40
WHEN MAX(e.created_at) >= NOW() - INTERVAL '7 days' THEN 30
WHEN MAX(e.created_at) >= NOW() - INTERVAL '14 days' THEN 15
ELSE 0
END AS activity_score,
-- Breadth score (0-30 points): unique users active in last 30 days
LEAST(COUNT(DISTINCT CASE WHEN e.created_at >= NOW() - INTERVAL '30 days' THEN e.user_id END) * 5, 30) AS breadth_score,
-- Onboarding score (0-30 points)
(MAX(CASE WHEN e.event_type = 'dashboard_created' THEN 10 ELSE 0 END) +
MAX(CASE WHEN e.event_type = 'team_member_invited' THEN 10 ELSE 0 END) +
MAX(CASE WHEN e.event_type = 'first_query_run' THEN 10 ELSE 0 END)) AS onboarding_score
FROM accounts a
JOIN users u ON u.account_id = a.id
LEFT JOIN events e ON e.user_id = u.id
GROUP BY a.id, a.name, a.plan_type
)
SELECT
id,
name,
plan_type,
activity_score + breadth_score + onboarding_score AS health_score,
CASE
WHEN activity_score + breadth_score + onboarding_score >= 70 THEN 'Healthy'
WHEN activity_score + breadth_score + onboarding_score >= 40 THEN 'At Risk'
ELSE 'Critical'
END AS health_status
FROM health_signals
ORDER BY health_score ASC;Run this weekly and sort by health_status = 'Critical' those are your CS calls for the week.
Your Database Is Your CS Tool
Customer success at scale isn't about calling every customer every week. It's about knowing which customers need attention right now and why before they've already decided to leave.
That intelligence is in your database. It just needs to be surfaced in a way your CS team can act on, without requiring an engineer to run queries every morning.
Start with the six metrics above. Build one dashboard. Set up one automated alert. The first time a CS manager catches a churning account because of a 14-day inactivity alert, you'll wonder why you didn't do this sooner.
Try AI for Database free connect your database and start asking customer health questions in plain English, no SQL required.