Watchtime & engagement
Per-content watchtime, completion, and engagement metrics for VOD and live (separate from legacy analytics datasets).
Watchtime & engagement
Per-content watchtime, unique viewers, completion, engagement buckets, and CDN bytes for VOD or live channels.
This is a separate API from the older Content Group / Individual analytics datasets (bytesperperiod, visitorsperperiod, and so on). For those, see Analytics.
When to use this
| Goal | Use |
|---|---|
| Plays / impressions / bandwidth time series (legacy datasets) | Analytics |
| Per-video (or per-channel) watchtime, completion rate, engagement % buckets | This guide → Engagement data |
Full parameter and response reference: Engagement data.
Endpoints
GET /v2/analytics/vod/watchtime-engagement
GET /v2/analytics/live/watchtime-engagement
Authenticate with X-Api-Key and send X-Format: default. Host: https://developer.dacast.com.
A successful call returns 200 and { "results": [ ... ] }. No data for the range → 200 with "results": [] (not 404).
Quick example (VOD)
curl -X GET "https://developer.dacast.com/v2/analytics/vod/watchtime-engagement?startdate=2026-10-09&enddate=2026-10-09&content-ids=aaaaaaaa-dc47-4838-b1cb-cd4ea208a670" \
-H "X-Api-Key: insertYourApiKeyHere" \
-H "X-Format: default"{
"results": [
{
"period": "2026-10",
"period-start": "2026-10-09",
"period-end": "2026-10-09",
"content-id": "vod-aaaaaaaa-dc47-4838-b1cb-cd4ea208a670",
"title": "Episode 1",
"total-plays": 2,
"unique-viewers": 2,
"total-watch-time": 1801.156,
"total-playtime": 1801.156,
"avg-watch-time-per-viewer": 900.578,
"completion-rate": 50,
"bytes-consumed": 1772696099,
"engagement-10": 0,
"engagement-25": 0,
"engagement-50": 1,
"engagement-75": 0,
"engagement-90": 0,
"engagement-100": 1
}
]
}Useful query parameters
| Param | Notes |
|---|---|
startdate / enddate | YYYY-MM-DD only. enddate is inclusive. Same-day ranges are valid. |
granularity | month (default) or day. Month grain: max range 366 days. |
content-ids | Optional comma-separated UUIDs, with or without vod- / live- prefix. |
page / perPage | Pagination (default page 1, perPage 100). |
timezone | Optional IANA zone (default UTC) used to interpret the date range. |
How to read a row
- Each row is one content × period (month or day).
periodisYYYY-MMorYYYY-MM-DDdepending ongranularity.period-start/period-endare inclusive and clipped to your request (a partial month does not look like a full calendar month).content-idis prefixed (vod-…orlive-…).total-watch-time- total seconds the content was actively watched (browser tab in focus).total-playtime- total seconds the content was played (player playing).unique-viewers- distinct viewers for that content × period. A viewer is identified byuser_idwhen present, otherwise bysession_id. Events with neither identity are not counted.avg-watch-time-per-viewer=total-watch-time / unique-viewers.completion-rate=engagement-100 / total-plays * 100(see Engagement buckets below).
Engagement buckets
Fields engagement-10, engagement-25, engagement-50, engagement-75, engagement-90, and engagement-100 count plays by the highest threshold their furthest watched point reached on the VOD (as a percentage of asset duration). A small duration tolerance is applied near the end of the asset.
They are not a cumulative funnel: a play is counted in exactly one bucket. A play that reached 100% is not also added into engagement-10 … engagement-90.
| Field | Meaning |
|---|---|
engagement-10 | Plays that peaked at 10% of duration (reached 10%, not yet 25%) |
engagement-25 | Plays that peaked at 25% (reached 25%, not yet 50%) |
engagement-50 | Plays that peaked at 50% (reached 50%, not yet 75%) |
engagement-75 | Plays that peaked at 75% (reached 75%, not yet 90%) |
engagement-90 | Plays that peaked at 90% (reached 90%, not yet 100%) |
engagement-100 | Plays that peaked at 100% (treated as completed) |
Between thresholds: a play that stops between two buckets lands in the lower one it already reached - for example 35% → engagement-25, 60% → engagement-50. A play that never reaches 10% is not counted in any engagement bucket.
Completion rate uses only the 100% bucket:
completion-rate = engagement-100 / total-plays * 100
Walkthrough of the example above
The sample row has total-plays: 2 and:
| Bucket | Count | Reading |
|---|---|---|
engagement-10 … engagement-25 | 0 | No play stopped in the 10–25% buckets |
engagement-50 | 1 | One play furthest point reached 50% (not 75%) |
engagement-75 … engagement-90 | 0 | No play stopped in the 75–90% buckets |
engagement-100 | 1 | One play furthest point reached 100% |
So: 1 of 2 plays completed → completion-rate is 50.
engagement-50 + engagement-100 = 2, which matches total-plays here. Plays with unknown duration (or no usable progress) may not appear in any bucket, so the sum of buckets can be less than total-plays.
Live channels
The live endpoint (GET /v2/analytics/live/watchtime-engagement) returns the same response shape for plays, unique viewers, watch/play time, and bytes. Engagement buckets are VOD-only (live has no fixed asset duration), so for live they are typically all 0 and completion-rate is not meaningful the same way. Prefer total-plays, unique-viewers, watch/play time, and bytes-consumed for live.
Live example
curl -X GET "https://developer.dacast.com/v2/analytics/live/watchtime-engagement?startdate=2026-10-01&enddate=2026-10-09&page=1&perPage=2" \
-H "X-Api-Key: insertYourApiKeyHere" \
-H "X-Format: default"Path is …/live/…; response shape matches VOD. Filter with bare channel UUIDs or live- prefixes via content-ids.
Related
- Reference: Engagement data
- Legacy bandwidth / plays / visitors: Analytics
Updated about 1 hour ago
