Custom Workout Assessment
A Custom Workout launched with isAssessment: true runs as usual and ends on fitness assessment results instead of the workout statistics: a workout score, an accuracy score, an activity level, the best exercise and the one to improve. It sends custom_assessment_completed with the numbers that screen shows.
What the run sends. Everything a Custom Workout sends stays the same: the loading events, workout_started, exercise_completed and workout_progress per exercise, workout_ended, then on the results screen workout_overview, exercise_overview and custom_assessment_completed in that order, the session save events when saving is on, and workout_completed followed by workout_exit_request (location: "statistic") when the user taps Continue or close. No completion overlay is shown, so there is no workout_completion_overlay_dismissed.
custom_assessment_completed is sent once per run, right after exercise_overview. The fields are under data:
| Field | Type | Description |
| workout_score | number | 0 to 100: the mean of the exercise scores, rounded. Every exercise counts, so an unfinished or skipped one pulls it down |
| accuracy_score | number | 0 to 100: form accuracy across the run, rounded |
| activity_level | string | From workout_score: "not_active" (up to 20), "somewhat_active" (up to 40), "active" (up to 70), "highly_active" (above 70) |
| is_partial | boolean | true when at least one exercise was not completed |
| completed_exercises | number | Exercises completed (rule below) |
| planned_exercises | number | Exercises in the list (rests not counted) |
| best_exercise | object or null | { exercise_id, exercise_title, accuracy }: the completed exercise with the highest accuracy |
| focus_exercise | object or null | { exercise_id, exercise_title, accuracy, top_mistake, mistake_count }: the completed exercise with the lowest accuracy (ties go to the one with more mistakes). top_mistake is its most frequent mistake, or null |
| exercises | array | One entry per exercise, below |
best_exercise and focus_exercise are both null when fewer than two exercises were completed, or when the same exercise is both.
Each entry of exercises:
| Field | Type | Description |
| exercise_id | string | As you sent it in customWorkoutExercises (always a string) |
| exercise_title | string | Exercise name |
| exercise_index | number | Its place in the workout as exercise_completed numbers it: 1-based, rests included |
| status | string | "completed", "unfinished" (started, not completed) or "skipped" (never reached: no time and no reps) |
| score | number | 0 to 100, rounded (rules below) |
| accuracy | number or null | 0 to 100; null when the exercise was never reached |
| reps | number | Reps counted |
| target_reps | number or null | The reps you set, null without one |
| time_spent | number | Seconds spent |
| target_time | number or null | The duration you set, null without one |
| hold_time | number | Seconds in the correct hold position |
| end_reason | string or null | "completed", "user_exit", "user_skip", "auto_skip", or null |
Completed. An exercise the user exited, skipped or that was auto-skipped is never completed. Otherwise it is completed when it reached its reps target, or, without a reps target, when it ran at least 85% of its duration (without either: as soon as it was reached). Give assessment tests a duration: a reps-only test the user cannot finish ends by auto-skip or Next and is reported unfinished.
Score per exercise (a missing duration counts as 30 s):
- Rep exercises with AI tracking: reps against a target, times the mean rep accuracy:
min(1, reps / target) x accuracy x 100. The target is yourreps; without one, KinesteX's Squats and Chair squat use 22, Push-ups and Knee push-ups 16, and other exercises one rep per 2 s of the duration. - Timed holds with AI tracking: seconds in the correct position over the duration.
- Without AI tracking (no model for the exercise, or motion tracking off): reps over your
repstarget, else time spent over the duration.
1{ "type": "custom_assessment_completed", "data": { "workout_score": 72, "accuracy_score": 88, "activity_level": "highly_active", "is_partial": false, "completed_exercises": 2, "planned_exercises": 2, "best_exercise": { "exercise_id": "101", "exercise_title": "Squats", "accuracy": 92 }, "focus_exercise": { "exercise_id": "102", "exercise_title": "Plank", "accuracy": 81, "top_mistake": "Keep your hips up", "mistake_count": 3 }, "exercises": [ { "exercise_id": "101", "exercise_title": "Squats", "exercise_index": 2, "status": "completed", "score": 82, "accuracy": 92, "reps": 10, "target_reps": 10, "time_spent": 24, "target_time": null, "hold_time": 0, "end_reason": "completed" } ] }, "timestamp": 1793368803120 }Restart. Restart on the results screen runs the same exercise list again in place; you do not send start again. The order is workout_restart (no workout_completed or exit for the restarted run), then a new workout_started when the run starts, and a new set of end events and custom_assessment_completed when it ends.