Overview
atRisk() returns a paginated list of users whose churn risk score exceeds a given threshold. Use it for bulk outreach campaigns, CS dashboards, or nightly reports.
For streaming all at-risk users without pagination management, see atRiskAll().
Signature
churn.atRisk(options?: AtRiskOptions): Promise<AtRiskResult>
AtRiskOptions
Minimum score to include (0–1). Default: 0.5. Must be a finite number between 0 and 1.
Filter to users on a specific plan (e.g. 'pro', 'enterprise'). Requires plan to have been set via identify().
Page size. Default: 50. Maximum: 200.
Pagination offset. Default: 0.
AtRiskResult
interface AtRiskResult {
users: AtRiskUser[]
total: number // total matching users (across all pages)
offset: number
limit: number
}
interface AtRiskUser {
userId: string
score: number
tier: RiskTier
signals: string[]
recommendation: string
}
Examples
Get high-risk users
const { users, total } = await churn.atRisk({ threshold: 0.7 })
console.log(`${total} high-risk users`)
for (const user of users) {
console.log(user.userId, user.score, user.signals)
}
Filter by plan
// Only enterprise users above 0.5 risk
const { users } = await churn.atRisk({
threshold: 0.5,
plan: 'enterprise',
})
Paginate all high-risk users
async function getAllAtRisk(threshold = 0.7): Promise<AtRiskUser[]> {
const all: AtRiskUser[] = []
let offset = 0
while (true) {
const { users, total } = await churn.atRisk({ threshold, limit: 100, offset })
all.push(...users)
offset += users.length
if (offset >= total) break
}
return all
}
Nightly CS report
// cron: every night at 9pm
const { users, total } = await churn.atRisk({ threshold: 0.65, limit: 200 })
await sendSlackMessage({
channel: '#customer-success',
text: `🚨 ${total} at-risk users tonight`,
blocks: users.slice(0, 10).map((u) => ({
userId: u.userId,
score: (u.score * 100).toFixed(0) + '%',
signals: u.signals.join(', '),
})),
})
Errors
| Code | When |
|---|
VALIDATION_ERROR | threshold is not between 0 and 1 |
UNAUTHORIZED | API key invalid |
TIMEOUT | Request timed out |