API reference

Playback counts API

Playback aggregates

HTTP reference. Generated from the backend contract. Browse endpoints below or download OpenAPI.

This group has 4 operations, generated from api/openapi.yaml. Filter by path, action, or authentication. Each endpoint lists its inputs; expand it for a request template and response codes. Templates need your own values and a schema-valid body.

Replace uppercase placeholders with your values. For a JSON request, save a body matching the schema in request.json. Cookie examples use a local cookie jar from an authenticated session.

Playback aggregates

GET/api/playback

List Playback Aggregates

Daily playback aggregates.

JSON returns at most 200 rows and is not rate limited. format=csv (or Accept text/csv without application/json) streams every matching row inside day_from to day_to (inclusive UTC days; defaults day_to today and day_from 30 days earlier; at most 366 days, else invalid_request) as CSV with a fixed header row (PlaybackAggregateCsv); only the CSV form spends the playback-export-org (30 per minute) and playback-export-ip (60 per minute) budgets.

Either form is one metered API request. Responses carry Vary Accept. A caller limited to screens (docs/screen-scope.md) must send screen_id and it must be a screen inside its scope (outside_screen_scope otherwise); the CSV forms follow the same rule.

Authentication
projectBearer OR dashboardSession
Request body
none
Operation ID
listPlaybackAggregates

Parameters

NameSend inRequired?Description
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.
screen_idqueryoptional
media_idqueryoptional
dayqueryoptionalUTC calendar day of the aggregate.
day_fromqueryoptionalFirst UTC day, inclusive. Excludes day. With day_to spans at most 366 days. CSV defaults it to 30 days before day_to.
day_toqueryoptionalLast UTC day, inclusive. Excludes day. CSV defaults it to today (UTC).
formatqueryoptionaljson (default), csv, xlsx or pdf. Omitted, an Accept header naming text/csv but not application/json selects csv. xlsx and pdf write the first 50000 rows of the same list.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/playback'

Responses

StatusMeaningBody and headers
200

Daily playback aggregates for the calling project, images and videos alike. One row per screen, media, and UTC day. Newest days first. Identifiers filter the caller's own rows and are never a cross-project lookup.

PlaybackAggregateList (application/json), PlaybackAggregateCsv (text/csv); headers: Vary, RateLimit-Policy, RateLimit
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
429

Stable rate_limited problem. Retry only after the authoritative Retry-After interval. Fixed-window denials also include the applicable RateLimit-Policy and RateLimit members; concurrency and byte-budget denials omit those optional disclosures.

Problem (application/problem+json); headers: Retry-After, RateLimit-Policy, RateLimit
403

outside_screen_scope - the caller is limited to screens and the screen, screen folder, selector or audience the request names or reaches is outside them (docs/screen-scope.md). An id outside the scope and an id that does not exist get the same answer; errors[0].screen_scope carries the caller's scope, and the write is refused whole, never narrowed.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/playback/plays

List Playback Plays

Per-play records: one row per accepted playback.media_started (or legacy playback.video_started) and one row per accepted playback.application_started (release_id set, media fields empty) of the calling project, oldest first by received_at, ties by insertion. from (inclusive) and to (exclusive) bound received_at; to defaults to now, from to 24 hours before to, and the range is at most 31 days (invalid_request otherwise).

The newest 5 seconds are not returned yet: the effective to is at most now minus 5 seconds (settle lag), so a live tail never skips a row that commits behind its cursor. screen_id, media_id, playlist_id (the playlist the start was shown from), and tag (a screen tag the screen carried when the play was received) filter.

A playlist_id page may hold fewer than limit rows, even none, with a next_cursor when a long stretch of plays of other playlists was scanned; null still ends the range.

JSON is a page of at most limit rows (default 200, at most 1000) with next_cursor, null at the end of the range; pass it back as cursor with the same filters. order=desc (or before) pages newest first within the same range: next_cursor is then the cursor of the oldest returned row, null at the start of the range, and is passed back as before (exclusive) with the same filters; order=asc with before is refused with invalid_request naming order, and cursor with a newest-first page naming cursor.

A newest-first page may hold fewer than limit rows, even none, with a next_cursor; null still ends it.

A later page never skips a row that existed when the earlier page was read and does not repeat one, except that a start the Player re-sent after an unacknowledged report (the same play_id, received a moment later) can appear again on a later page; the CSV stream lists it once. format=csv (or Accept text/csv without application/json) streams every play from cursor to the end of the range as CSV (PlaybackPlayCsv), newest first below before with order=desc; limit is refused with CSV.

Metering is per request: every JSON page costs one API request credit, while one CSV stream of the whole range costs one. Every plays request (page or stream) spends the playback-export-org (30 per minute) and playback-export-ip (60 per minute) budgets.

A stream bounds each write (15 seconds) and ends when the client disconnects; if it fails after the 200 header the connection is aborted, so an export that reads to a clean end is complete. Responses carry Vary Accept. Plays are kept for the plan's event retention (30 days is the shipped floor; plan-based retention uses the plan's own 7- or 90-day window).

A caller limited to screens (docs/screen-scope.md) must send screen_id and it must be a screen inside its scope (outside_screen_scope otherwise); the CSV forms follow the same rule.

Authentication
projectBearer OR dashboardSession
Request body
none
Operation ID
listPlaybackPlays

Parameters

NameSend inRequired?Description
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.
fromqueryoptionalInclusive lower bound on received_at. Defaults to 24 hours before to.
toqueryoptionalExclusive upper bound on received_at. Defaults to now. to - from is at most 31 days.
screen_idqueryoptional
media_idqueryoptional
playlist_idqueryoptionalOnly plays shown from this playlist.
tagqueryoptionalA screen tag the screen carried when the play was received.
cursorqueryoptionalnext_cursor of the previous page, with the same filters. Opaque.
orderqueryoptionalasc pages oldest first with cursor; desc pages newest first with before. before implies desc; order=asc with before is refused.
beforequeryoptionalPages newest first, strictly older than this position: the next_cursor of a newest-first page, with the same filters. Opaque.
limitqueryoptionalJSON page size. Refused with CSV.
formatqueryoptionaljson (default), csv, xlsx or pdf. Omitted, an Accept header naming text/csv but not application/json selects csv. xlsx and pdf write the first 50000 rows of the same list.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/playback/plays'

Responses

StatusMeaningBody and headers
200A page of plays, or the CSV stream.PlaybackPlayList (application/json), PlaybackPlayCsv (text/csv); headers: Cache-Control, Vary, RateLimit-Policy, RateLimit
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
401

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
429

Stable rate_limited problem. Retry only after the authoritative Retry-After interval. Fixed-window denials also include the applicable RateLimit-Policy and RateLimit members; concurrency and byte-budget denials omit those optional disclosures.

Problem (application/problem+json); headers: Retry-After, RateLimit-Policy, RateLimit
403

outside_screen_scope - the caller is limited to screens and the screen, screen folder, selector or audience the request names or reaches is outside them (docs/screen-scope.md). An id outside the scope and an id that does not exist get the same answer; errors[0].screen_scope carries the caller's scope, and the write is refused whole, never narrowed.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/playback/totals

Get Playback Totals

Play totals of the calling project over inclusive UTC days, read from the daily rollups: by=day returns one row per day with plays (screen_id or media_id narrows it to one screen or media), by=screen and by=media rank the busiest screens or media (top, at most 100), and by=screen_day returns the day series of the top screens (top at most 10). day_to defaults to today (UTC) and day_from to 29 days before it.

A day series spans at most 366 days (92 when narrowed to a screen or media); a ranking at most 92. Counts include every start the project has recorded, including those stored before play rollups existed.

Rollups follow ingestion by up to about 21 minutes. truncated is true when a ranking was built from slices of a window too large for one read: it covers the best keys of each slice. Not rate limited. One metered API request.

A caller limited to screens (docs/screen-scope.md) must send screen_id and it must be a screen inside its scope (outside_screen_scope otherwise); the CSV forms follow the same rule.

Authentication
projectBearer OR dashboardSession
Request body
none
Operation ID
getPlaybackTotals

Parameters

NameSend inRequired?Description
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.
formatqueryoptionaljson (default) returns the report as JSON. csv, xlsx and pdf return the same rows as a file attachment (every page of a paged report, up to 50000 rows).
byqueryoptionalday: plays per day; screen, media: the busiest keys; screen_day: the day series of the top screens.
day_fromqueryoptionalFirst UTC day, inclusive. Defaults to 29 days before day_to. A day series spans at most 366 days (92 when narrowed to a screen or media), a ranking at most 92.
day_toqueryoptionalLast UTC day, inclusive. Defaults to today (UTC).
screen_idqueryoptional
media_idqueryoptional
topqueryoptionalHow many screens or media a ranking returns (at most 10 for by=screen_day). Refused with by=day.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/playback/totals'

Responses

StatusMeaningBody and headers
200Totals of the requested grouping.PlaybackTotals (application/json); headers: Cache-Control
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
401

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
403

outside_screen_scope - the caller is limited to screens and the screen, screen folder, selector or audience the request names or reaches is outside them (docs/screen-scope.md). An id outside the scope and an id that does not exist get the same answer; errors[0].screen_scope carries the caller's scope, and the write is refused whole, never narrowed.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/playback/completeness

Get Playback Completeness

How many of the plays the screens made reached the backend, and where the missing ones were. Players number their media starts, so a start that never arrived leaves a hole in the numbering, for example when a screen stays offline past its 24 hour report queue or the queue drops reports.

Over the inclusive UTC days day_from to day_to (day_to defaults to today, UTC, and day_from to 29 days before it; the window spans at most 92 days) the answer holds measured_plays, the numbered plays that arrived; missing_plays, the numbers the Players skipped; completeness, measured_plays over their sum, null when both are 0; days, the same three figures for each day that has any, oldest first, a hole counted on the UTC day of the play after it; and gaps, the holes newest first, each with its screen_id, its day, from and to (the start times of the plays on either side of it) and missing_plays. screen_id narrows days and gaps to one screen; limit (default 100, at most 500) caps gaps, and truncated is true when more exist.

A switched-off screen makes no plays and leaves no gap. Plays without a number (older Players, starts stored before play numbers) are not measured: they are in play_count of GET /api/playback/totals and in none of these figures. Not rate limited. One metered API request.

A caller limited to screens (docs/screen-scope.md) must send screen_id and it must be a screen inside its scope (outside_screen_scope otherwise); the CSV forms follow the same rule.

Authentication
projectBearer OR dashboardSession
Request body
none
Operation ID
getPlaybackCompleteness

Parameters

NameSend inRequired?Description
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.
formatqueryoptionaljson (default) returns the report as JSON. csv, xlsx and pdf return the same rows as a file attachment (every page of a paged report, up to 50000 rows).
day_fromqueryoptionalFirst UTC day, inclusive. Defaults to 29 days before day_to. With day_to spans at most 92 days.
day_toqueryoptionalLast UTC day, inclusive. Defaults to today (UTC).
screen_idqueryoptional
limitqueryoptionalThe most gaps to list, newest first.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/playback/completeness'

Responses

StatusMeaningBody and headers
200The completeness of the window and its gaps.PlaybackCompleteness (application/json); headers: Cache-Control
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
401

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
403

outside_screen_scope - the caller is limited to screens and the screen, screen folder, selector or audience the request names or reaches is outside them (docs/screen-scope.md). An id outside the scope and an id that does not exist get the same answer; errors[0].screen_scope carries the caller's scope, and the write is refused whole, never narrowed.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)