> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flowsbuilt.com/llms.txt
> Use this file to discover all available pages before exploring further.

# score()

> Get the real-time churn risk score for a single user.

## Overview

`score()` returns a risk assessment for a user — a 0–1 score, a tier classification, the signals driving the score, and a recommendation for what to do.

## Signature

```typescript theme={null}
churn.score(
  userId: string,
  options?: ScoreOptions
): Promise<RiskScore>
```

## Parameters

<ParamField path="userId" type="string" required>
  The user to score.
</ParamField>

<ParamField path="options.signal" type="AbortSignal">
  Cancel the request.
</ParamField>

## RiskScore

```typescript theme={null}
interface RiskScore {
  userId: string
  score: number         // 0.0 (healthy) → 1.0 (churning)
  tier: RiskTier        // 'low' | 'medium' | 'high'
  signals: string[]     // reasons driving the score
  recommendation: string
}
```

### Score tiers

| Tier       | Range      | Meaning                     |
| ---------- | ---------- | --------------------------- |
| `'low'`    | 0.0 – 0.39 | Healthy — no action needed  |
| `'medium'` | 0.4 – 0.69 | Watch — consider a check-in |
| `'high'`   | 0.7 – 1.0  | At-risk — act immediately   |

### Example signals

* `no_login_7d` — no login in 7 days
* `no_login_14d` — no login in 14 days
* `feature_usage_drop` — feature usage fell >50% week-over-week
* `support_spike` — 3+ support tickets in 7 days
* `export_all_data` — exported all data (exit intent signal)
* `cancellation_page_viewed` — viewed the cancellation page
* `billing_failed` — recent payment failure
* `trial_expiring` — trial expires within 3 days
* `downgrade_initiated` — initiated a plan downgrade

## Examples

### Get risk score

```typescript theme={null}
const risk = await churn.score('user_123')

console.log(risk.score)          // 0.82
console.log(risk.tier)           // 'high'
console.log(risk.signals)        // ['no_login_7d', 'support_spike', 'export_all_data']
console.log(risk.recommendation) // 'This user is at high risk. Reach out immediately.'
```

### Conditional action based on tier

```typescript theme={null}
const risk = await churn.score(userId)

switch (risk.tier) {
  case 'high':
    await sendSlackAlert({ userId, score: risk.score, signals: risk.signals })
    await queueOutreachEmail(userId, 'high_risk_template')
    break
  case 'medium':
    await queueOutreachEmail(userId, 'check_in_template')
    break
  case 'low':
    // healthy — no action
    break
}
```

### In a cron job

```typescript theme={null}
// Run daily for all active users
const users = await db.getActiveUsers()

for (const user of users) {
  const risk = await churn.score(user.id)
  if (risk.tier === 'high') {
    await alertCustomerSuccess(user.id, risk)
  }
}
```

### With abort on timeout

```typescript theme={null}
const controller = new AbortController()
const timeout = setTimeout(() => controller.abort(), 3000)

try {
  const risk = await churn.score('user_123', { signal: controller.signal })
  return risk
} finally {
  clearTimeout(timeout)
}
```

## Errors

| Code               | When                                                  |
| ------------------ | ----------------------------------------------------- |
| `VALIDATION_ERROR` | `userId` is empty                                     |
| `NOT_FOUND`        | User has no tracked events — score cannot be computed |
| `UNAUTHORIZED`     | API key invalid                                       |
| `TIMEOUT`          | Request exceeded timeout                              |
