# WebView messages (Tracking endpoint)

The Tracking endpoint emits structured messages during real-time tracking.

Use them to drive UI and business logic.

### How messages are delivered

In a browser iframe, messages are sent via `window.postMessage`.

In mobile apps, they go through the WebView bridge.

Some integrations stringify the payload.

Handle both cases:

* `event.data` is an object
* `event.data` is a JSON string

### Typical V3 flow (real-time)

1. `initialization` messages while the model and camera load.
2. `posture` messages until placement is good.
3. Optional placement countdown (still `posture` messages).
4. `counter` starts once tracking is active.
5. Optional advanced outputs, depending on flags:
   * `form_score`
   * `progression`
   * `recommendations`
   * `keypoints`
   * `angles`
6. Jump flows (when using `jump_analysis` / `air_time_jump`):
   * `jump_calibration` → `jump_started` → `jump_height`
   * optional `jump_discarded`

### Message types (Tracking)

#### `initialization` (realtime)

Sent while the page loads and initializes.

Fields:

* `type` (`string`) — always `"initialization"`.
* `message` (`string`) — human-readable status.
* `ready` (`boolean`) — `true` only when tracking can start.

Example:

```json
{
  "type": "initialization",
  "message": "Loading pose model",
  "ready": false
}
```

#### `error` (realtime)

Sent when the configuration or runtime fails.

Fields:

* `type` (`string`) — always `"error"`.
* `code` (`string`) — machine-readable error code.
* `message` (`string`) — human-readable description.
* `details` (`object`, optional) — extra debug info.

Example:

```json
{
  "type": "error",
  "code": "invalid_exercise",
  "message": "Unknown exercise: split",
  "details": {
    "exercise": "split"
  }
}
```

Common codes you should handle:

* `missing_token` — `token` is missing.
* `invalid_token` — token is invalid or revoked.
* `invalid_exercise` — `exercise` is missing or unknown.
* `developer_features_not_allowed` — plan-gated flag used on Free plan.
* `webgl_unavailable` — `poseBackend=webgl` requested but not available.
* `wasm_unavailable` — `poseBackend=wasm` requested but cannot load.
* `camera_permission_denied` — user denied camera access.
* `camera_not_found` — no camera available.
* `jump_analysis_missing_height` — `userHeightCm` required for `jump_analysis`.

#### `posture` (realtime placement)

Sent continuously during placement.

It tells you what the user should do to be “ready”.

Fields:

* `type` (`string`) — `"posture"`.
* `message` (`string`) — guidance text for the user.
* `direction` (`string`) — placement direction hint. Example: `"in-frame"`.
* `ready` (`boolean`) — `true` when tracking can start.
* `requirements` (`array`, optional) — unmet requirements.
* `countdownSecondsLeft` (`number`, optional) — present when countdown is enabled.

Example:

```json
{
  "type": "posture",
  "message": "Step back. Keep your full body in frame.",
  "direction": "in-frame",
  "ready": false,
  "requirements": ["full_body_visible"],
  "countdownSecondsLeft": 0
}
```

#### `counter` (realtime)

Sent when exercise tracking is active.

For repetition exercises, it increments on each validated rep.

For duration exercises, it increments over time (seconds).

Fields:

* `type` (`string`) — `"counter"`.
* `current_count` (`number`) — reps or seconds.
* `exercise` (`string`, optional) — movement key.

Example:

```json
{
  "type": "counter",
  "exercise": "squat",
  "current_count": 6
}
```

#### `form_score` (realtime, optional)

Sent when form scoring is enabled for the exercise.

This is a compact “how good is the current posture” signal.

Fields:

* `type` (`string`) — `"form_score"`.
* `score` (`number`) — `0` to `100`.
* `label` (`string`, optional) — example: `"good"`, `"needs_work"`.

Example:

```json
{
  "type": "form_score",
  "score": 82,
  "label": "good"
}
```

#### `recommendations` (realtime, plan-gated)

Sent when `recommendations=true`.

Fields:

* `type` (`string`) — `"recommendations"`.
* `data` (`array<string>`) — feedback strings, ordered by priority.

Example:

```json
{
  "type": "recommendations",
  "data": [
    "Keep your knees aligned with your toes.",
    "Lower your hips a bit more."
  ]
}
```

#### `progression` (realtime, plan-gated)

Sent when `progression=true`.

This is usually a rep-phase progress signal.

Fields:

* `type` (`string`) — `"progression"`.
* `value` (`number`) — `0` to `100`.

Example:

```json
{
  "type": "progression",
  "value": 47
}
```

#### `keypoints` (realtime, plan-gated)

Sent when `keypoints=true`.

Fields:

* `type` (`string`) — `"keypoints"`.
* `data` (`array<object>`) — keypoints.

Keypoint object:

* `name` (`string`) — landmark name.
* `x` (`number`) — pixels.
* `y` (`number`) — pixels.
* `score` (`number`) — confidence `0 → 1`.

Example:

```json
{
  "type": "keypoints",
  "data": [
    { "name": "nose", "x": 322.3, "y": 78.1, "score": 0.99 },
    { "name": "left_shoulder", "x": 366.4, "y": 132.7, "score": 0.98 }
  ]
}
```

#### `angles` (realtime, plan-gated)

Sent when `angles=true`.

Fields:

* `type` (`string`) — `"angles"`.
* `data` (`object`) — computed angles.

Example:

```json
{
  "type": "angles",
  "data": {
    "left_side": {
      "knee_angle": { "from_hip_to_ankle": 164 }
    },
    "right_side": {
      "knee_angle": { "from_hip_to_ankle": 168 }
    }
  }
}
```

#### Jump messages (realtime, custom exercises)

These fire only for:

* `exercise=jump_analysis`
* `exercise=air_time_jump`

**`jump_calibration` (jump\_analysis only)**

Sent during calibration.

```json
{
  "type": "jump_calibration",
  "ready": false,
  "message": "Hold still"
}
```

**`jump_started`**

Sent once per detected jump.

```json
{
  "type": "jump_started"
}
```

**`jump_discarded`**

Sent when a jump attempt is detected but rejected.

Typical reasons are missing hips, occlusion, or unstable baseline.

```json
{
  "type": "jump_discarded",
  "reason": "hips_not_visible"
}
```

**`jump_height`**

Sent during measurement and/or when a jump completes.

Payload differs slightly by jump type.

```json
{
  "type": "jump_height",
  "jumpHeightCm": 31.8,
  "final": true
}
```

**`jump_summary`**

Sent for upload-video analyses.

It is not typically emitted in real-time mode.

### Related

* Query params: [Query parameters (Tracking endpoint)](/posetracker-api/use-posetracker-on-real-time-camera-webcam/query-parameters-tracking-endpoint.md)
* Upload messages: [WebView / native messages](/posetracker-api/use-posetracker-on-uploaded-files/upload-tracking-endpoint-video-and-image/webview-native-messages.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://posetracker.gitbook.io/posetracker-api/use-posetracker-on-real-time-camera-webcam/webview-messages-tracking-endpoint.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
