Plans & Programs
Events for workout plans and programs.
| Event | Data Fields | Description |
| plan_unlocked | id: string, img: string, title: string, date: string | Plan unlocked/selected |
| plan_opened | id: string | Plan result screen rendered. Fires for both goal-based and personalized plans |
| plan_onboarding_plan_created | data: { plan_id: string, plan_type: string } | A new plan was created from onboarding/assessment. Does NOT fire on revisits to an existing personalized plan |
| plan_progression_saved | data: { planType: string, weekNumber: number, dayNumber: number, source?: string } | Plan day progression was saved successfully after a plan workout finished. planType is "goal-based" or "personalized". source: "offline_outbox" is present only when the save was recovered after a lost connection — live saves omit it |
| plan_progression_failed | data: object | Plan progression save failed (network/server error) |
| personalized_plan_exit | workout: string, date: string | Exit from personalized plan |
| remind_me_later_clicked | - | User tapped "Remind me later" on the Assessment screen inside the plan-onboarding flow. Only fires from the plan-onboarding page |
Note on plan tracking: When you launch a plan workout directly via the SDK, you can pass planId, planType, and progressWorkoutId in the initial PostMessage configuration so the SDK associates the workout session with the correct plan. After the workout finishes, you'll receive either plan_progression_saved (success) or plan_progression_failed (error). See Plan Context configuration for details.
Offline save recovery: if a save fails (e.g. the user loses connection on the results screen), the result is stored locally and automatically re-sent when the connection returns or the app is reopened. plan_progression_saved (and workout_session_saved) can therefore arrive after a delay instead of only at save time — make your handler idempotent and treat source as optional.