Phoenix Gamification
Streaks

Streaks Overview

This guide explains how Phoenix streaks are modeled so you can design engagement mechanics before touching the Admin API. It focuses on the configuration shape you submit when creating a streak definition.

1. Mental Model

  • Streak – a named engagement tracker scoped to a tenant. Each streak owns a configuration document that defines which events qualify, what condition must be met within each time window, and what rewards unlock at milestones.
  • Time window – the period during which a user must satisfy the streak condition (e.g., daily, weekly, rolling 24-hour). Missing a window resets the consecutive count to zero.
  • User streak – an individual user's progress for a specific streak definition, including their consecutive count and current window progress.

Once a configuration is active, every ingested event is evaluated against its rules. Matching events update the user's window progress; when the window condition is satisfied, the consecutive count increments.

2. Lifecycle & Status

StatusMeaningTypical Use
activeStreak is processing events and tracking user progress normally.Default after creation.
pausedFrozen state—no window advancement, no breaks, no event processing.Maintenance windows or holiday pauses.
archivedSoft delete—no processing, but historical data preserved for reporting.Sunset legacy streaks without losing user data.

Switching back to active re-enables processing immediately for future events.

3. Configuration Snapshot

Every streak config follows this top-level structure:

{
  "event_types": ["user.login"],
  "expression": null,
  "window": {
    "type": "calendar",
    "period": "daily",
    "timezone": "America/New_York",
    "reset_time": "00:00"
  },
  "condition": {
    "type": "count",
    "min": 1
  },
  "milestones": [
    { "threshold": 7, "reward_item_id": null, "repeatable": false },
    { "threshold": 30, "reward_item_id": "a1b2c3d4-...", "repeatable": false }
  ],
  "at_risk_seconds": 3600
}

Each section is detailed below.

4. Event Types & Filtering

Event Types

Specify which events count toward the streak. Supports exact matches and wildcard patterns:

  • "user.login" – exact match
  • "game.*" – matches game.started, game.completed, etc.
  • "*" – matches all events (use with caution)

Expression Filters (Optional)

For advanced filtering, add an expression that evaluates event attributes:

{
  "expression": {
    "and": [
      {
        "condition": {
          "field": "attrs.platform",
          "operator": "eq",
          "value": "mobile"
        }
      },
      {
        "condition": {
          "field": "attrs.session_duration",
          "operator": "gte",
          "value": 300
        }
      }
    ]
  }
}

Supported operators:

  • Equality: eq, ne
  • Comparison: gt, gte, lt, lte
  • Membership: in, not_in
  • Existence: exists
  • Text: contains, starts_with, ends_with

If expression is omitted or null, all events matching the event_types qualify.

5. Time Windows

TypeDescriptionConfiguration Fields
calendarFixed boundaries aligned to calendar periods (daily/weekly/monthly).period, timezone, reset_time
rollingSliding window from the user's last qualifying activity.duration_seconds

Calendar Windows

{
  "type": "calendar",
  "period": "daily",
  "timezone": "UTC",
  "reset_time": "00:00"
}
  • period: daily, weekly, or monthly
  • timezone: IANA timezone (e.g., America/Los_Angeles, Europe/London)
  • reset_time: Time of day when windows reset (HH:MM format)

Weekly windows reset on Sunday; monthly windows reset on the 1st.

Rolling Windows

{
  "type": "rolling",
  "duration_seconds": 86400
}

Rolling windows give users flexibility—they have 24 hours (or your configured duration) from their last qualifying event to satisfy the next window.

6. Window Conditions

The condition defines what a user must accomplish within each window to maintain their streak.

TypeDescriptionExample Use Case
countNumber of qualifying events"Log in at least once per day"
sumSum of a numeric field across events"Earn 100 points per week"
distinctCount of unique values in a field"Play 3 different game modes"

Count Condition

{
  "type": "count",
  "min": 1
}

Sum Condition

{
  "type": "sum",
  "field": "attrs.points_earned",
  "min": 100
}

Distinct Condition

{
  "type": "distinct",
  "field": "attrs.game_mode",
  "min": 3
}

7. Milestones & Rewards

Milestones unlock when a user reaches specific consecutive streak counts:

{
  "milestones": [
    { "threshold": 7, "reward_item_id": null, "repeatable": false },
    {
      "threshold": 30,
      "reward_item_id": "uuid-of-reward-item",
      "repeatable": false
    },
    {
      "threshold": 100,
      "reward_item_id": "uuid-of-special-reward",
      "repeatable": true
    }
  ]
}
FieldDescription
thresholdConsecutive count required to unlock (must be positive)
reward_item_idOptional UUID linking to your rewards system
repeatableIf true, milestone can be earned again after the streak breaks

When a user hits a milestone, Phoenix emits a streak.milestone_reached event that your systems can consume to grant rewards.

8. At-Risk Notifications

The optional at_risk_seconds field triggers a warning before a window closes:

{
  "at_risk_seconds": 3600
}

When the window is about to end and the user hasn't satisfied the condition, Phoenix emits a streak.at_risk event. Use this to send push notifications encouraging users to complete their streak before it breaks.

9. Streak Events

Phoenix emits real-time events as streaks progress:

Event TypeWhen It Fires
streak.incrementedUser satisfied the window condition; count increased
streak.brokenWindow closed without condition satisfied; count reset
streak.milestone_reachedUser hit a milestone threshold
streak.at_riskWindow ending soon without condition satisfied

Subscribe to these events via NATS to trigger notifications, update UIs, or sync with external systems.

10. Best Practices Checklist

  • Choose window types that match user behavior—daily for habitual actions, weekly for larger commitments.
  • Start with simple count conditions before adding sum or distinct complexity.
  • Use meaningful milestone thresholds (7, 14, 30, 100) that feel achievable yet rewarding.
  • Configure at_risk_seconds to give users enough time to react (1–4 hours before window close).
  • Test streak configurations in a staging tenant with short windows before production.
  • Document each streak's purpose for your support and marketing teams.

With these concepts in mind, proceed to Create Streak for API-specific instructions on provisioning streak definitions.