# AI Trainer Events

Events emitted by the [AI Trainer Chat](/docs/ai-trainer-chat) view. On Swift/Kotlin/Flutter they arrive through the generic `custom_type` / `CustomType` case with the parsed JSON as a dictionary/map.

| Event | Data Fields | Description |
|-------|-------------|-------------|
| trainer_schedule_next_workout | scheduledFor: string, sessionType: string | User picked a date/time for their next session. `scheduledFor` is `YYYY-MM-DDTHH:MM` device-local time; `sessionType` is `"workout"` or `"assessment"` (treat missing as `"workout"`) |
| open_subscription_flow | source: string, date: string | A non-subscribed user tried to generate a workout — present your subscription flow and post `subscription_result` back (`"purchased"` or `"dismissed"`) |
| trainer_assessment_started | date: string | User began the in-app fitness assessment |
| trainer_assessment_completed | date: string, results: object, fitnessLevel: string | Assessment finished, with per-exercise reps and level (`results.squats` / `results.pushups`) plus an overall `fitnessLevel` (`"beginner"` / `"intermediate"` / `"advanced"`). A test that was skipped (for example because of an injury) arrives as `{ reps: null, level: null }` |
| trainer_assessment_skipped | date: string, reason: string | User chose to set their fitness level manually (`reason: "set_manually"`) |
| trainer_profile_updated | source: string, profile: object | The user's fitness profile changed. Carries the full current profile; `source` is `"onboarding"`, `"assessment"`, `"chat"`, or `"host"` (an echo of your own `update_trainer_profile`). Persist it on your side |
| trainer_profile_onboarding | stage: string, data: object, date: string | One applied step of the onboarding wizard. `data` holds just that step's answer. Fields that also exist in the `profile` object use the same names; `body_parts`, `training_style`, `equipment` and `duration` carry fields the profile doesn't have. Stages: `profile`, `fitness_goals`, `goal_recommendation`, `body_parts`, `injuries`, `injury_detail`, `training_style`, `fitness_level`, `equipment`, `duration`, `other_preferences`, `workout_frequency`. Also sent again when the user edits an answer card in the chat before the plan starts generating |
| trainer_profile_clicked | profile: object or null, date: string | User opened the profile while `customProfileAction: true`. Open your own profile screen. `profile` has the same shape as in `trainer_profile_updated` (`null` when no profile is stored yet or it could not be loaded) |
| trainer_calendar_clicked | date: string | User tapped the calendar button while `customCalendarAction: true`. Open your own progress or calendar screen |
| trainer_workout_days_updated | days: string[], daysPerWeek: number, preferredTime: string | The user picked (or edited) the weekdays they want to train on. `days` are lowercase `"mon"`..`"sun"` in week order; `preferredTime` is device-local `HH:MM`. Same answer also arrives as the `workout_frequency` onboarding stage and in the profile. See the [workout days guide](/docs/ai-trainer-chat#workout-days) |
| workout_exit_request | - | The user exited a workout that was launched from the trainer |

Full payload examples and the subscription handshake: [AI Trainer Chat guide](/docs/ai-trainer-chat) and the [subscription gating guide](/docs/guides/guide-subscription-gating).

---
Source: https://www.kinestex.com/docs/data-points/trainer-events · Index: https://www.kinestex.com/llms.txt
