LA start: two triggers
A Live Activity can be started by two paths. Both converge on the same token registration flow.Trigger 1: User follows a live match
Trigger 2: Orchestrator detects match going live
MatchOrchestrator runs a 30-second polling loop. It detects matches transitioning to live status and handles startup recovery — if the backend restarts while matches are live, the Orchestrator picks them up on the next cycle and creates any missing PENDING records.
LA update
Once a Live Activity is active (has a registered update token), it receives score updates through the event-driven pipeline.LA end: four reasons
A Live Activity can end for four distinct reasons. Each has a different trigger path.1. Match ends
2. User unfollows
3. User dismisses LA on device
4. Token becomes invalid
Token invalidation is self-healing. The Orchestrator’s 30-second loop detects followers who should have an active LA but don’t, and re-sends push-to-start. This handles device restarts, OS-terminated activities, and token rotation.
Token management
Three token types
Token rotation
iOS can rotate theupdateToken for an active Live Activity at any time. The flow:
- iOS fires
pushTokenUpdateson the Activity object TokenManagerobserves the new token, deduplicates (skips if same as current)- Posts to
POST /matches/:matchId/activity-tokenwith the new token - Backend updates the
live-activitiesrecord in-place (same PK/SK, new token value)
Multi-device support
A single user can have active LAs on multiple devices simultaneously. Thelive-activities table uses userId#deviceId as the sort key, so each device gets its own record. When the LACoordinator fans out pushes, it sends to all active tokens for a match — regardless of how many belong to the same user.
iOS service architecture
The old monolithicLiveActivityService has been split into three focused managers:
TokenManager
Handles all token observation and registration.- Observes
pushToStartTokenchanges on app launch - Observes
pushTokenUpdatesfor each active Live Activity - Deduplicates tokens (skips POST if token hasn’t changed)
- Retries failed token registrations
LifecycleManager
Manages the Activity object lifecycle.- Calls
Activity.request()to create new LAs - Restores existing activities on app relaunch (checks ActivityKit state)
- Runs a stale check: if no update received in 30 minutes, ends the LA locally
- Adopts push-started activities (activities created via push-to-start that need local tracking)
FollowManager
Manages the follow/unfollow user intent and local state.- Calls
POST /user/follow/matchandDELETE /user/follow/match - Persists followed match IDs in
UserDefaultsfor instant UI state - Retries pending unfollows on next app launch (handles offline unfollow)
- Drives the bell icon states:
DynamoDB schema
live-activities table
active-matches table
Related pages
- Live score pipeline — how scores flow from SportMonks through the EventBus to APNs
- Match following — the user action that triggers LA creation
- Device registration — push token types and multi-device support