Retention¶
How the platform measures, predicts, and acts on player retention. The goal is to keep players engaged once they're past first-login, recover players who drift toward inactivity, and produce honest engagement metrics for operators and region owners.
This document is a target spec — it describes how the retention machinery should work end-to-end. Inline status (✅/🚧/📐) lives in FEATURES; here we describe target state.
Engagement metrics¶
Daily / Weekly / Monthly Active¶
The standard funnel:
| Metric | Definition | Window |
|---|---|---|
| DAU | Distinct players with ≥ 1 logged action in the last 24 hours | 24h |
| WAU | Distinct players with ≥ 1 logged action in the last 7 days | 7d |
| MAU | Distinct players with ≥ 1 logged action in the last 30 days | 30d |
| Stickiness | DAU ÷ MAU | derived |
A "logged action" is any event recorded by PlayerActivityService.track_activity — login, trade, combat, sector move, dock, planet land, warp.
Online now¶
PlayerActivityService.get_online_player_count returns the size of the activity:online_players Redis set. Membership is added on track_login, removed on track_logout, and TTL'd if the session goes silent.
Session metrics¶
Per session captured in Redis under activity:session:{player_id} with TTL 24h:
{
"login_at": "...",
"last_activity_at": "...",
"actions_count": int,
"trades_count": int,
"trade_volume": int,
"combat_events": int,
"sectors_visited": [...],
"session_duration_minutes": int (computed at logout)
}
AnalyticsService._calculate_average_session_time produces the rolling mean over a configurable window (default 7 days).
Retention rate¶
retention_rate(N days) =
(players whose created_at <= now - N days AND is_active = true)
÷
(players whose created_at <= now - N days)
AnalyticsService._calculate_retention_rate(days) provides 7-day and 30-day rolling rates. These are surfaced on the admin dashboard and exposed via the analytics API.
Activity tracking pipeline¶
[Game action]
|
v
[PlayerActivityService.track_activity]
| (stores event in Redis)
v
[PlayerActivity table] <-- async writeback for durable analytics
|
v
[AnalyticsService aggregations]
|
v
[Admin dashboard / region governor reports]
Redis ↔ Postgres split¶
- Redis stores hot, ephemeral session and event data with TTL — fast reads, no schema migrations.
- Postgres stores
PlayerActivity,PlayerSession,PlayerAnalyticsSnapshotfor durable analytics, retention math, and behavioral analysis.
Writes happen first to Redis (low latency); a writeback job (target: every 5 minutes) drains recent events into Postgres for durable storage. On Redis loss the most-recent ~5 minutes of telemetry can be lost; live gameplay is unaffected.
Inactivity decay¶
Several systems decay when a player goes quiet. Each is independent.
ARIA relationship¶
Player.aria_relationship_score decays by 1 point per day inactive (apply_inactivity_decay in the ARIA service). Never falls below 0. Reset to current value on next login. See FEATURES/gameplay/aria-companion.md.
Faction reputation¶
FactionService.apply_reputation_decay runs per player periodically:
- Reputation above +100 or below −100 drifts toward neutral when last updated > 30 days ago.
- Drift rate: 1 point/day past the 30-day threshold.
- Maximum decay per call: 50 points.
- Never crosses the ±100 floor (decay stops at the neutral band).
- Skipped if
decay_pausedoris_locked.
Personal reputation¶
Weekly tick decays toward zero:
- score > 0: score -= 5 (floor 0).
- score < 0: score += 5 (ceiling 0).
Applied to all active players. See SYSTEMS/bounty-and-reputation.md.
Regional standing¶
RegionalMembership.reputation_score does not auto-decay by default. A region's owner can opt in to per-region decay rules (target spec).
Turn regeneration¶
Turns regenerate at a fixed rate regardless of activity (see SYSTEMS/turn-regeneration.md) — they accumulate up to a cap. Inactivity does not cost turns; it just leaves them maxed.
At-risk signals¶
The behavior analyzer (PlayerBehaviorAnalyzer.analyze_player_behavior) produces a profile per player including a confidence score and behavioral cluster. The retention layer reads this to derive at-risk signals:
| Signal | Threshold | Meaning |
|---|---|---|
dormant_session |
No login in 7+ days | Player is drifting |
lapsed |
No login in 30+ days | High churn risk |
declining_session_length |
Last 5 sessions trending down (>30% drop) | Engagement waning |
early_logout_streak |
3 consecutive sessions < 5 minutes | Frustration / boredom |
negative_combat_streak |
Recent kill/death ratio inverted | Player getting farmed |
economic_loss_streak |
Recent net credit loss > 50% of holdings | Trading struggles |
social_isolation |
Solo player with no team / messages in 14 days | Social hook missing |
Signals are computed nightly; flagged players land in a re-engagement queue.
Re-engagement campaigns¶
The platform supports several re-engagement levers, applied based on signal severity.
Email / push reminder¶
For lapsed players, a templated email is queued (target spec — uses platform mail service, opt-in only). Frequency cap: at most one per 14 days.
In-game ARIA welcome-back¶
When a player returns after dormant_session, ARIA's first dialogue references the gap explicitly and summarises what changed:
"Welcome back, Captain. It's been 12 days. Two new sectors opened in your home cluster, and Equipment prices at Trade Hub Beta are at a 30-day low. Want a route?"
This is gated on aria_consciousness_level ≥ 2 (enough memories to summarise meaningfully).
Returning-player turn bonus¶
Player.turns is topped up by a "welcome back" bonus if last login was > 7 days ago. Bonus: min(500, days_inactive × 50). Capped to prevent abuse from alt accounts.
Daily-quest seed¶
The daily-quest system (see FEATURES/gameplay/missions.md) seeds at-risk players with easier quests on return — explicit "first day back" tier. Avoids overwhelming with hard objectives.
Seasonal events¶
Quarterly seasonal events (Galactic Trade Festival, Frontier Days, Founders' Anniversary) provide: - Time-limited missions with unique rewards. - Increased reputation gain rates with all factions. - Special cosmetic rewards tied to login frequency during the event. - Region-wide buffs (decreased tax, free turn regeneration boost).
Events are scheduled on a fixed calendar; entry conditions are simple ("be logged in during the event window"). Rewards scale with consecutive-day participation.
Region-owner retention metrics¶
Region owners (see OPERATIONS/multi-regional.md) get a dashboard with their region's active_players_30d, total_trade_volume, and a simplified retention curve. This drives the regional governance feedback loop — owners who can't keep players engaged see it directly.
Region.active_players_30d is recomputed nightly from the underlying activity data.
Privacy¶
Activity tracking is OWASP-compliant:
- All event data is keyed by player_id, with explicit access controls.
- Players can request a data export of their activity history.
- Players can opt out of analytics (engagement events still need to fire for game state, but they are not aggregated for retention or behavioral analysis).
- IP addresses and user-agent strings are stored only for security logs (ARIASecurityLog), not retention analytics.
- Data retention: raw events 90 days, aggregated snapshots indefinitely (with no PII).
Source map¶
| Concern | Path (target) |
|---|---|
| Activity tracking (Redis layer) | services/gameserver/src/services/player_activity_service.py |
| Behavior analysis (ML clustering, anomaly) | services/gameserver/src/services/player_behavior_analyzer.py |
| Aggregate analytics | services/gameserver/src/services/analytics_service.py |
| Models | services/gameserver/src/models/player_analytics.py (PlayerSession, PlayerActivity, PlayerAnalyticsSnapshot) |
| ARIA inactivity decay | services/gameserver/src/services/aria_personal_intelligence_service.py:apply_inactivity_decay |
| Faction decay | services/gameserver/src/services/faction_service.py:apply_reputation_decay |
| Personal reputation decay | services/gameserver/src/services/personal_reputation_service.py:apply_weekly_decay |
| Region 30d active recompute | services/gameserver/src/services/regional_governance_service.py |
| Re-engagement scheduler | services/gameserver/src/services/retention_scheduler.py (target — not yet split out) |
Related¶
OPERATIONS/multi-regional.md— regional retention as a region-owner KPI.OPERATIONS/aria.md— ARIA's role in welcome-back interactions.SYSTEMS/turn-regeneration.md— turns are not coupled to retention but interact with returning-player bonuses.SYSTEMS/bounty-and-reputation.md— personal reputation decay.