Streaks
Track consecutive user engagement with configurable streak mechanics, grace periods, and freezes.
Streaks track consecutive user engagement over time. Define a qualifying event (like app_open or workout_completed), and Amba automatically tracks current count, longest count, and streak status.
How it works
- Admin defines a streak definition with a qualifying event and period
- When a user tracks the qualifying event, their streak is automatically updated
- If the user misses a period, the streak resets (unless a grace period or freeze is configured)
- Streak evaluation also runs daily in the background to catch broken streaks
SDK usage
Get user's streaks
Each streak includes:
Qualify a streak manually
Automatic qualification
When you track an event that matches a streak's qualifying_event, the streak is automatically qualified:
Streak mechanics
Period
daily— user must qualify once per calendar dayweekly— user must qualify once per calendar week
Grace period
Set grace_period_hours to give users extra time before their streak breaks. For example, a 6-hour grace period means the user has until 6 AM the next day.
Streak freezes
When freeze_enabled is true, users can freeze their streak to prevent it from breaking. max_freezes controls how many freezes a user can hold at once.
Shields (freezes)
In partner-facing copy we call freezes "shields" — same field on the wire (freezes_remaining), different word for the user. A streak with 1 shield that misses its qualifying period is automatically converted from active to frozen instead of broken, and freezes_remaining is decremented by 1. The streak's current_count is preserved — never punish a missed day with a red number; show "your streak is safe" copy instead.
Field semantics
Field on streak_definitions | Type | Meaning |
|---|---|---|
freeze_enabled | boolean | Master switch. If false, missing the period always breaks the streak. |
max_freezes | integer | Cap on how many shields a user can hold. Both auto-grant and admin grant clamp at this value. |
freezes_per_n_events | integer | null | Auto-grant rule: every N consecutive qualifying events grants 1 shield. null disables auto-grant — shields only come from explicit admin grants. |
Field on user_streaks | Type | Meaning |
|---|---|---|
freezes_remaining | integer | Number of shields currently in the user's pool. Drops by 1 when a shield is consumed on a miss. |
status | enum | 'active' | 'frozen' | 'broken'. frozen is the moment a shield protected the streak. |
Auto-grant rule
Set freezes_per_n_events = 5, max_freezes = 2 to get the partner spec verbatim: every 5 completed missions grants the user 1 shield, capped at 2 concurrent shields.
The grant fires on the increment that crosses the threshold (i.e. when current_count % freezes_per_n_events === 0). Resets and restarts do NOT grant a shield.
Shield consumption emits streak_shielded
When the daily streak-evaluation workflow finds a streak that missed its window AND freezes_remaining > 0, the row flips to frozen, freezes_remaining is decremented, and an engagement event is emitted:
Use this event to render in-app "your streak is safe" copy or to drive a re-engagement push. The same row also gets a streak_events audit entry with event_type='freeze' so the admin user-detail dump renders the full timeline.
Admin grant endpoint
Bumps user_streaks.freezes_remaining by count, clamped at max_freezes. Returns the updated row. 404 if no user_streaks row exists for the (user, definition) pair — the streak workflow lazily-creates that row on the first qualifying event, so the user must have at least one event before you can grant.
Admin API reference
| Method | Path | Description |
|---|---|---|
POST | /admin/streaks | Create streak definition |
GET | /admin/streaks | List streak definitions |
Client API reference
| Method | Path | Description |
|---|---|---|
GET | /client/streaks | Get user's streak states |
POST | /client/streaks/:id/qualify | Record qualifying event |
POST /client/streaks/:id/qualify
Records a qualifying event for a streak. Handles:
- Already qualified today (returns current state, no-op)
- Consecutive day (increments count)
- Broken streak (resets to 1)
Response:
MCP tools
| Tool | Description |
|---|---|
amba_create_streak | Create a streak definition with qualifying event, period, grace, and freeze settings |
Example
Reading streaks in Expo
Database tables
| Table | Purpose |
|---|---|
streak_definitions | Definitions with qualifying event, period, grace, freeze settings |
user_streaks | Per-user streak state (current count, longest, status) |
streak_events | Event log (increment, reset, freeze) |