Get YouTube video retention curve
Returns the audience retention curve for a single YouTube video, plus the video's duration for rendering the curve on a time axis. The curve has up to 100 points (elapsedVideoTimeRatio 0.01-1.0) aggregated over the whole date range; YouTube does not support per-day retention breakdowns.
audienceWatchRatio is the absolute share of viewers watching at that point in the video and can exceed 1 (rewinds and looping, common on Shorts). relativeRetentionPerformance compares against videos of similar length (0 = worst, 0.5 = median, 1 = best). YouTube returns an empty curve for videos with very few views or before analytics processing completes (2-3 day delay).
Requires yt-analytics.readonly scope (re-authorization may be needed).
API key authentication - use your Zernio API key as a Bearer token
In: header
Query Parameters
The YouTube video ID (e.g., "dQw4w9WgXcQ")
The Zernio account ID for the YouTube account
Start date (YYYY-MM-DD). Defaults to the video's publish date (lifetime curve).
dateEnd date (YYYY-MM-DD). Defaults to 3 days ago (YouTube data latency).
dateResponse Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
import Zernio from '@zernio/node';const zernio = new Zernio({ apiKey: process.env.ZERNIO_API_KEY });const { data } = await zernio.analytics.getYouTubeVideoRetention({ query: { videoId: 'video_abc123', accountId: 'account_abc123', },});console.log(data);{
"success": true,
"accountId": "65f1a2b3c4d5e6f7a8b9c0d1",
"videoId": "zF7Gp4jnDa0",
"title": "what's your choice?",
"publishedAt": "2026-05-20T12:00:00Z",
"durationSeconds": 24,
"dateRange": {
"startDate": "2026-05-20",
"endDate": "2026-06-09"
},
"retentionCurve": [
{
"elapsedVideoTimeRatio": 0.01,
"audienceWatchRatio": 1.6956,
"relativeRetentionPerformance": 0.73665,
"startedWatching": 280331,
"stoppedWatching": 5348,
"totalSegmentImpressions": 478466
},
{
"elapsedVideoTimeRatio": 0.02,
"audienceWatchRatio": 1.678,
"relativeRetentionPerformance": 0.73865,
"startedWatching": 385,
"stoppedWatching": 11790,
"totalSegmentImpressions": 473492
}
],
"scopeStatus": {
"hasAnalyticsScope": true
}
}{
"error": "string"
}{
"error": "Unauthorized"
}{
"error": "Analytics add-on required",
"code": "analytics_addon_required"
}{
"error": "Access denied to this account"
}{
"error": "Video not found on this YouTube channel",
"type": "not_found",
"code": "video_not_found",
"param": "videoId"
}{
"success": false,
"error": "To access video retention analytics, please reconnect your YouTube account to grant the required permissions.",
"code": "youtube_analytics_scope_missing",
"scopeStatus": {
"hasAnalyticsScope": false,
"requiresReauthorization": true,
"reauthorizeUrl": "https://accounts.google.com/o/oauth2/auth?client_id=..."
}
}{
"success": false,
"error": "string"
}Get YouTube demographics GET
Returns audience demographic insights for a YouTube channel, broken down by age, gender, and/or country. Age and gender values are viewer percentages (0-100). Country values are view counts. Data is based on signed-in viewers only, with a 2-3 day delay. Requires the Analytics add-on.
List conversations with inbox analytics GET
Per-conversation listing with per-row totals + first/last message timestamps. The inbox analog of GET /v1/analytics (posts listing) — same filter shape, same pagination, same sort/order semantics. Use as the entry point for the per-conversation analytics drawer at /v1/analytics/inbox/conversations/{conversationId}. Rows are enriched with the conversation's participant info (`participantName`, `participantUsername`, `participantPicture`) and last-message preview by joining the Conversation document scoped to the caller's team. Max date range is 365 days.