
Watch time, retention, and impressions sound like three numbers a single API call should return together. AIOZ Stream's Analytics API splits them across three different endpoints instead, and one of those eight documented metrics, retention, isn't available from the simplest one at all. That's not an oversight. It's a real constraint worth understanding before wiring up dashboard widgets that assume every metric works the same way.
TL;DR:
AIOZ Stream's Analytics API is built around three distinct endpoints, and picking the wrong one for a given dashboard widget is the easiest mistake to make before actually reading through all three. POST /api/analytics/metrics/data/:metric/:aggregation returns a single number, a metric reduced by an aggregation like count, total, average, or sum. POST /api/analytics/metrics/bucket/:metric/:breakdown returns that same kind of metric, but split across a dimension, by media ID, country, device type, browser, and so on, useful for a leaderboard or a geographic breakdown. POST /api/analytics/metrics/timeseries/:metric/:interval returns a value per hour or per day across a date range, the shape an actual trend chart needs. All three take a required from/to UNIX timestamp range and an optional filter_by object (media_ids, media_type, continents, countries, device_types, os, browsers, tags), so filtering works consistently across all three even though the output shape doesn't.
The documented metrics, with their exact definitions: play, "the number of times your content has been played." start, "the number of times playback was started." end, "the number of times playback has ended with the content watched until the end." impression, "the number of times your content has been loaded and was ready for playback." watch_time, "the cumulative time in seconds that the user has spent watching your content." view, "the number of times your content has been watched in playback." retention, "the total amount of time a user has continuously engaged with your content." play_rate, "the ratio that calculates the number of plays your content receives divided by its impressions."
Worth being direct about something the documentation doesn't clarify: play, start, and view read as near-synonyms. All three describe a viewer engaging with playback, and nothing in the docs states what operationally distinguishes a "play" from a "start" from a "view." A reasonable guess is that play fires on the initial user action (clicking the play button), start fires when the player actually begins rendering frames (which can lag behind the click on a slow connection), and view counts something closer to a qualifying watch session, but that's inference, not documented fact. Building a dashboard that reports all three side by side without checking whether they actually diverge in real traffic risks displaying three numbers that are effectively the same metric measured three times, confusing rather than clarifying for whoever reads the dashboard. The practical fix: pull all three for a real video with meaningful traffic before deciding which ones earn a spot on the dashboard, rather than assuming distinct value from the names alone.
The aggregated-metrics endpoint's documented :metric list is play, start, end, impression, watch_time, view, six values, verified directly against the docs. retention and play_rate are absent from that list; they only appear as valid values on the breakdown and timeseries endpoints. That's not an inconsistency to work around, it lines up with what retention actually means as a concept. A retention curve, the standard way the video industry visualizes this metric, is a graph plotting the percentage of viewers still watching at each point in a video's timeline, not a single number. A steep early drop typically signals a mismatch between what a thumbnail promised and what the video delivers, while a sudden cliff partway through usually marks a specific moment, an awkward transition or a slow section, where attention breaks. None of that is visible in one aggregate figure. Collapsing retention into a single sum or average the way watch_time can be summed would throw away the one thing that makes it useful, so AIOZ's decision to only expose it through bucket or timeseries, where it can actually be plotted as a curve, is a defensible design choice once you see what the metric is for, even though the docs themselves never explain the reasoning.
A real analytics dashboard usually needs four kinds of widgets, and each one maps to exactly one of the three endpoints once the retention constraint above is accounted for. A single summary number, total plays this month, average watch time per session, pulls from the aggregated endpoint, one request per number. A trend line, plays or impressions per day over the last 30 days, pulls from the timeseries endpoint with interval=day. A retention curve for one video pulls from the timeseries endpoint too, filtered to a single media_id, since that's the only way to get retention as a curve rather than a flat total. A leaderboard, top 10 videos by watch time, or a geographic breakdown, watch time by country, pulls from the bucket endpoint with the relevant breakdown value, media-id or country.
A worked example, pulling a week of watch time as a daily trend line:
POST /api/analytics/metrics/timeseries/watch_time/day
{
"from": 1788652800,
"to": 1789257600,
"filter_by": {
"media_ids": ["abc123"]
}
}The response returns one data entry per day in range, each with a metric_value and an emitted_at timestamp, exactly the shape a charting library expects without further reshaping. Swap watch_time for retention on the same request and the same shape becomes a retention curve instead of a watch-time trend, the endpoint and interval logic doesn't change, only the metric name does.
A dashboard with four or five widgets, each refreshing on a schedule, adds up in request volume faster than a single integration test suggests, especially once real users start loading it concurrently. AIOZ Stream's documented limits cap reads at 500 requests per minute, comfortable for a single dashboard session but worth checking against actual expected concurrent usage before assuming it'll never be an issue, the rate limits article covers the exact headers and handling pattern for exactly this kind of read-heavy integration.
Which endpoint should I use to get a single summary number, like total plays this month?
The aggregated-metrics endpoint, POST /api/analytics/metrics/data/:metric/:aggregation, returns one reduced value per request.
Why can't I get retention from the aggregated-metrics endpoint?
Retention and play_rate are only documented on the breakdown and timeseries endpoints. Retention specifically only makes sense as a curve over time or a video's timeline, not a single aggregate figure, which is likely why it's excluded from the single-number endpoint.
What's the actual difference between play, start, and view?
The documentation defines all three but doesn't state what operationally distinguishes them in practice. Pull all three for a real, high-traffic video and compare before assuming a dashboard needs to display all of them separately.
How do I build a per-video retention curve?
Use the timeseries endpoint with metric=retention, filtered to a single media_id via filter_by, and a day or hour interval depending on the video's length.
Can I filter analytics by country or device type?
Yes. All three endpoints accept the same filter_by object, including continents, countries, device_types, os, and browsers, alongside media_ids, media_type, and tags.
Will a busy analytics dashboard hit AIOZ Stream's rate limits?
Reads are capped at 500 requests per minute. A handful of widgets refreshing periodically stays well under that, but concurrent dashboard sessions or aggressive polling intervals are worth checking against that ceiling directly rather than assuming it never applies.

Mesh, SFU, and MCU solve the same problem, getting N people in a call to see each other, in three very differently priced ways. The math behind why mesh breaks past 4 people, and why every major platform runs SFU instead of MCU.

A traditional CDN edge is a company-owned data center, one of a few hundred. AIOZ's edge is a community-operated node, one of 328,094. Here's what that structural difference actually means for caching, coverage, and guarantees.

MP4 and WebM aren't independent formats, they're restricted, standardized descendants of MOV and MKV. The real lineage explains the trade-offs better than a feature table, and none of the four is actually what a streaming platform delivers.

AV1 shares VP9's royalty-free pitch, but hardware decode is moving fast and Netflix's own numbers are strong. Here's what actually changed, and whether AIOZ Stream supports it today.

Most DRM comparisons stop at platform lists. The two things that actually matter: security tiers gate resolution, and a historical encryption mismatch used to break Apple playback silently, until the industry converged on one fix.

AIOZ Stream's own docs don't mention DRM anywhere. Here's what DRM actually protects, who really needs it, and what AIOZ Stream offers instead, an access-control model closer to Cloudflare Stream than to Mux's full multi-DRM support.