Docs

Playback & Engagement Events

Session, milestone, completion rate, and player error events.

These events are generated by the telemetry aggregator as it processes playback heartbeats, and by daily metric jobs for aggregate thresholds. They reflect viewer behaviour after a video is published. For the envelope format, shared headers, and retry policy, see Outbound Webhooks.

Telemetry-driven events flush when the aggregator processes stored heartbeats. The delay between a viewer watching and the webhook firing depends on how frequently the aggregator runs: around five minutes in typical setups.

Examples reuse the following placeholders throughout this page: organization_id11111111-1111-1111-1111-111111111111, video id → 00000000-0000-4000-8000-00000000aa01, session id → 33333333-3333-4333-8333-333333333333.


playback.session.ended

When it fires. The telemetry aggregator processes a session ended playback event. Watch time and completion are derived from heartbeats and video duration.

{
  "id": "evt_e3f4a5b6-c7d8-4901-e234-567890123456",
  "type": "playback.session.ended",
  "created_at": "2026-05-09T22:00:00.000Z",
  "organization_id": "11111111-1111-1111-1111-111111111111",
  "data": {
    "video": {
      "id": "00000000-0000-4000-8000-00000000aa01",
      "external_id": "c3d7e9a1-2b4f-4c6d-8e0a-1f3b5d7c9e0a",
      "status": "complete",
      "title": "My video.mp4",
      "duration_ms": 125400,
      "width": 1920,
      "height": 1080,
      "collection_id": "22222222-2222-4222-8222-222222222222"
    },
    "session": {
      "id": "33333333-3333-4333-8333-333333333333",
      "watch_time_seconds": 87,
      "completion_percent": 69,
      "country": "BR",
      "device_type": "desktop",
      "referrer": "https://example.com/page"
    }
  }
}
PathTypeDescription
data.videoobjectSee shared data.video.
data.session.idstringPlayback session UUID.
data.session.watch_time_secondsnumberEstimated watch time: heartbeat interval × count.
data.session.completion_percentnumber0-100; max position reached divided by duration.
data.session.countrystringOptional; ISO country code derived from session geo.
data.session.device_typestringOptional; coarse device class (for example desktop, mobile).
data.session.referrerstringOptional; referrer URL captured when the session started.

playback.cta.clicked

When it fires. The player ingests a CTA click telemetry event with a cta_id attached.

{
  "id": "evt_f4a5b6c7-d8e9-4012-f345-678901234567",
  "type": "playback.cta.clicked",
  "created_at": "2026-05-09T22:01:00.000Z",
  "organization_id": "11111111-1111-1111-1111-111111111111",
  "data": {
    "video": {
      "id": "00000000-0000-4000-8000-00000000aa01",
      "external_id": "c3d7e9a1-2b4f-4c6d-8e0a-1f3b5d7c9e0a",
      "status": "complete",
      "title": "My video.mp4",
      "duration_ms": 125400,
      "width": 1920,
      "height": 1080,
      "collection_id": "22222222-2222-4222-8222-222222222222"
    },
    "session": { "id": "33333333-3333-4333-8333-333333333333" },
    "cta": {
      "id": "66666666-6666-4666-8666-666666666666",
      "position_seconds": 45
    }
  }
}
PathTypeDescription
data.videoobjectSee shared data.video.
data.session.idstringSession UUID.
data.cta.idstringCTA UUID.
data.cta.position_secondsnumberOptional; player position (in seconds) when the CTA was clicked, if reported.

playback.milestone.25

When it fires. During telemetry aggregation, a heartbeat shows the viewer reached ≥ 25% of the video's duration in that session. Fires at most once per session per milestone (deduplication via the milestone tracking table).

{
  "id": "evt_a5b6c7d8-e9f0-4123-a456-789012345678",
  "type": "playback.milestone.25",
  "created_at": "2026-05-09T22:02:00.000Z",
  "organization_id": "11111111-1111-1111-1111-111111111111",
  "data": {
    "video": {
      "id": "00000000-0000-4000-8000-00000000aa01",
      "external_id": "c3d7e9a1-2b4f-4c6d-8e0a-1f3b5d7c9e0a",
      "status": "complete",
      "title": "My video.mp4",
      "duration_ms": 125400,
      "width": 1920,
      "height": 1080,
      "collection_id": "22222222-2222-4222-8222-222222222222"
    },
    "session": { "id": "33333333-3333-4333-8333-333333333333" },
    "milestone": 25
  }
}
PathTypeDescription
data.videoobjectSee shared data.video.
data.session.idstringSession UUID.
data.milestonenumberAlways 25 for this event type.

playback.milestone.50

When it fires. Same conditions as playback.milestone.25, for the 50% threshold.

{
  "id": "evt_b6c7d8e9-f0a1-4234-b567-890123456789",
  "type": "playback.milestone.50",
  "created_at": "2026-05-09T22:03:00.000Z",
  "organization_id": "11111111-1111-1111-1111-111111111111",
  "data": {
    "video": {
      "id": "00000000-0000-4000-8000-00000000aa01",
      "external_id": "c3d7e9a1-2b4f-4c6d-8e0a-1f3b5d7c9e0a",
      "status": "complete",
      "title": "My video.mp4",
      "duration_ms": 125400,
      "width": 1920,
      "height": 1080,
      "collection_id": "22222222-2222-4222-8222-222222222222"
    },
    "session": { "id": "33333333-3333-4333-8333-333333333333" },
    "milestone": 50
  }
}
PathTypeDescription
data.videoobjectSee shared data.video.
data.session.idstringSession UUID.
data.milestonenumberAlways 50 for this event type.

playback.milestone.75

When it fires. Same conditions, for the 75% threshold.

{
  "id": "evt_c7d8e9f0-a1b2-4345-c678-901234567890",
  "type": "playback.milestone.75",
  "created_at": "2026-05-09T22:04:00.000Z",
  "organization_id": "11111111-1111-1111-1111-111111111111",
  "data": {
    "video": {
      "id": "00000000-0000-4000-8000-00000000aa01",
      "external_id": "c3d7e9a1-2b4f-4c6d-8e0a-1f3b5d7c9e0a",
      "status": "complete",
      "title": "My video.mp4",
      "duration_ms": 125400,
      "width": 1920,
      "height": 1080,
      "collection_id": "22222222-2222-4222-8222-222222222222"
    },
    "session": { "id": "33333333-3333-4333-8333-333333333333" },
    "milestone": 75
  }
}
PathTypeDescription
data.videoobjectSee shared data.video.
data.session.idstringSession UUID.
data.milestonenumberAlways 75 for this event type.

playback.milestone.100

When it fires. Same conditions, for the 100% threshold: the session reached (or exceeded) the full video duration.

{
  "id": "evt_d8e9f0a1-b2c3-4456-d789-012345678901",
  "type": "playback.milestone.100",
  "created_at": "2026-05-09T22:05:00.000Z",
  "organization_id": "11111111-1111-1111-1111-111111111111",
  "data": {
    "video": {
      "id": "00000000-0000-4000-8000-00000000aa01",
      "external_id": "c3d7e9a1-2b4f-4c6d-8e0a-1f3b5d7c9e0a",
      "status": "complete",
      "title": "My video.mp4",
      "duration_ms": 125400,
      "width": 1920,
      "height": 1080,
      "collection_id": "22222222-2222-4222-8222-222222222222"
    },
    "session": { "id": "33333333-3333-4333-8333-333333333333" },
    "milestone": 100
  }
}
PathTypeDescription
data.videoobjectSee shared data.video.
data.session.idstringSession UUID.
data.milestonenumberAlways 100 for this event type.

video.view.milestone

When it fires. During daily metric aggregation, cumulative views for a video cross 100, 1 000, or 10 000 for the first time. Only video.id is sent under data: the full data.video snapshot is not included.

{
  "id": "evt_e9f0a1b2-c3d4-4567-e890-123456789012",
  "type": "video.view.milestone",
  "created_at": "2026-05-10T08:00:00.000Z",
  "organization_id": "11111111-1111-1111-1111-111111111111",
  "data": {
    "video": { "id": "00000000-0000-4000-8000-00000000aa01" },
    "milestone_views": 1000
  }
}
PathTypeDescription
data.video.idstringVideo UUID. No other video fields are sent.
data.milestone_viewsnumberOne of 100, 1000, 10000.

video.completion_rate.threshold

When it fires. While updating daily metrics, the average completion rate (watch time ÷ plays ÷ duration) crosses 40% or 50% from below to at-or-above. Fires once per threshold per direction per day.

{
  "id": "evt_f0a1b2c3-d4e5-4678-f901-234567890123",
  "type": "video.completion_rate.threshold",
  "created_at": "2026-05-10T08:01:00.000Z",
  "organization_id": "11111111-1111-1111-1111-111111111111",
  "data": {
    "video": { "id": "00000000-0000-4000-8000-00000000aa01" },
    "completion_rate_percent": 45,
    "threshold_percent": 40,
    "date": "2026-05-10"
  }
}
PathTypeDescription
data.video.idstringVideo UUID. No other video fields are sent.
data.completion_rate_percentnumberRounded completion rate after the metric update.
data.threshold_percentnumberConfig threshold crossed: 40 or 50.
data.datestringAggregate calendar day (YYYY-MM-DD).

playback.error

When it fires. The player reports a playback error event for a session. The error code is forwarded as-is from the telemetry payload; unknown is used as a fallback if the code is missing.

{
  "id": "evt_a1b2c3d4-e5f6-4789-a012-3456789abcde",
  "type": "playback.error",
  "created_at": "2026-05-09T22:10:00.000Z",
  "organization_id": "11111111-1111-1111-1111-111111111111",
  "data": {
    "video": {
      "id": "00000000-0000-4000-8000-00000000aa01",
      "external_id": "c3d7e9a1-2b4f-4c6d-8e0a-1f3b5d7c9e0a",
      "status": "complete",
      "title": "My video.mp4",
      "duration_ms": 125400,
      "width": 1920,
      "height": 1080,
      "collection_id": "22222222-2222-4222-8222-222222222222"
    },
    "session": { "id": "33333333-3333-4333-8333-333333333333" },
    "error": { "code": "network_failed" }
  }
}
PathTypeDescription
data.videoobjectSee shared data.video.
data.session.idstringSession UUID.
data.error.codestringError code from the telemetry event; unknown if absent.