The counter message is sent each time the rep count changes. For upload video, a final counter is emitted once processing ends (final: true).
Fields
type: "counter"
current_count: number — total counted reps so far
final: boolean (optional) — true when processing has finished (upload video)
form_score: object (optional) — score for the rep that was just counted (or current state when final:true)
score: number (0–100)
avg_score: number (running average)
grade: "A" | "B" | "C" | "D" | "F"
Concrete examples
Standalone form_score event (if you see it)
If a form_score-only message exists in other contexts (e.g. live feedback while a rep is in progress), it must not be treated as the authoritative grade for a counted rep.
Single source of truth for counted reps:counter.form_score.
Tips for developers: minGrade vs client-side filtering
Server-side filtering (recommended): minGrade
If you set minGrade=B, PoseTracker only increments current_count for reps graded A or B. This means:
current_count becomes your “valid reps” count
each counter event already corresponds to a valid rep
Client-side filtering (if you don’t want server filtering)
If you do not set minGrade, you receive every counted rep with its grade inside counter.form_score. You can maintain your own strict count:
Pseudo-logic:
if payload.form_score.grade is in ["A","B"], increment your local strict counter
Errors
(keep your existing error section; ensure it includes plan restriction errors and invalid_exercise)