Schedules and takeover
A screen's campaigns and playlist schedule entries are levels of one stack. The server decides what each screen plays from the top: its takeover, the campaigns that reach it (--priority first, then the newest), the screen's own schedule entries in order, the playlist assigned with screen assign, then the default playlist of the nearest screen folder that sets one. The first level that holds plays. Switches land within about a minute of a boundary, and Players need no update. A sheet of schedule lines for many screens imports in one step: see Schedule import.
A level holds while all its rules hold: from and until, weekly windows, monthly rules, dates, except dates, a data condition and an interaction condition. A monthly rule is a day of the month (1 to 31; a month without that day skips it) or the nth weekday (1 to 4, or -1 for the last) with a weekday; a dates item is one date; both take optional start and end times and otherwise cover the whole day. An except date removes every occurrence that starts on it, overnight tails included, and an overnight occurrence belongs to the date it starts. data is {key, path?, equals?} and holds while that card data exists or equals the scalar. interaction is {idle_s} (5 to 3600, default 60): the level plays while someone is using the screen by touch, click or key and drops back after idle_s seconds without input, as an interactive page above an attract loop. displays lists the video wall outputs (1 to 12) the level plays on. covers is full (the page, default), main, or header, footer or side, a strip drawn over the page that needs a playlist made for that region; see strips. start is next_item (default), which waits for the current item to end, or on_time, which interrupts it at the edge. A Player that resolves its own stack plays interaction, data, strip and displays levels; campaign explain reports the level for any other Player as off with reason stack_only (needs a Player that resolves its own stack).
screen show, screen list, and the schedule and takeover writes below return effective_playlist ({id, source, entry_id?, until?}, where source is takeover, campaign, schedule, default, or folder), takeover, and playlist_schedule. entry_id is the campaign id for campaign, the entry id for schedule, and the folder id for folder. until is the next moment the choice is known to change. screen show --human prints it in the screen's timezone, as in Assigned: pl_LUNCH (schedule entry lunch until 2026-08-14 15:00 America/Los_Angeles) or Assigned: pl_LUNCH (campaign cmp_LUNCH until 2026-08-14 15:00 America/Los_Angeles) (UTC, labelled, when the screen has no zone); JSON output keeps RFC 3339 instants. Human schedule tables are labelled with the screen timezone, and screen list --human adds an ASSIGNED column when any listed screen plays something other than its default playlist.
| Problem code | Exit | Meaning |
|---|---|---|
invalid_request | 8 | The screen has no assigned default playlist (next is screen assign), or a named playlist cannot be assigned. |
screen_archived | 5 | An archived screen refuses schedules and takeovers. next is screen unarchive. |
revision_conflict | 6 | The --expect-rev revision was stale. |
playlist_format_mismatch | 5 | A playlist's format does not match the screen: a wall playlist on a screen whose wall has another shape, or a strip entry (covers header, footer or side) laid out on none of the screen's displays. |
feature_not_in_plan | 8 | The plan lacks the feature a new entry uses: schedule change control for a new paused entry, video walls for displays naming display 2 or beyond. Pricing lists the plans. |
rate_limited | 7 | Schedule and takeover writes share per-minute limits: 600 per organization, 20 per screen, and 60 per IP. Wait for retry_after_seconds. |
With one screen id, these commands return the updated screen and --expect-rev guards its revision. Several ids, --tag TAG or --folder ID (every active screen in that screen folder and in every folder inside it) run as one fleet request with the fleet envelope and exit rules; each screen fails alone, and the CLI pauses and resumes automatically when the project budget is exhausted. Under Propose access, or in a project that requires review for agent changes, a write to one screen or to the whole fleet selection answers pending_review: the command succeeds (exit 0) with data.review and a pending_review warning, data.next is screenrig reviews show ID, and nothing changes on screen until a person approves it, so do not repeat the write. --note tells the reviewer why; see Reviews. On a screen in a protected folder the write waits for a second approver at every access level.
screen schedule show#
Show a screen's playlist schedule and the playlist it currently selects.
screen schedule show <id>| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<id> | string | yes | none | The scr_ screen id. |
screenrig screen schedule show scr_CAFEdata holds entries (empty when the screen has no schedule), updated_at and effective_playlist. The JSON output can go straight back to screen schedule set --file.
screen schedule set#
Replace the playlist schedule on a screen or a fleet.
screen schedule set (<id>... | --tag TAG | --folder ID) --file FILE [--expect-rev REVISION] [--note TEXT]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<id>... | string | one of <id>, --tag or --folder | none | One or more scr_ screen ids. Several ids run as one fleet request. |
--tag TAG | string | one of <id>, --tag or --folder | none | Every active screen carrying this tag. |
--folder ID | string | one of <id>, --tag or --folder | none | Every active screen in this sfd_ screen folder and the folders inside it. |
--file FILE | path | yes | none | The schedule document, or - for stdin. The JSON of screen schedule show is accepted back. |
--expect-rev REVISION | string | no | none | One screen id only. Optional revision precondition. |
--note TEXT | string | no | none | A note for the person who reviews the change: plain text, at most 280 characters. Ignored when the change applies at once. |
screenrig screen schedule set scr_CAFE --file dayparts.json
screenrig screen schedule set --tag Cafe --file dayparts.json
screenrig screen schedule set --folder sfd_01EXAMPLEFOLDER000000000 --file dayparts.jsonEvery playlist a schedule names is validated as an assignment, and the screen needs an assigned default playlist. The entries' times are read in the screen's own timezone. When no entry holds, the assigned playlist plays. If a scheduled playlist later cannot be shown, its entries are skipped and screen.playlist_unavailable is recorded.
screen schedule clear#
Remove the playlist schedule from a screen or a fleet.
screen schedule clear (<id>... | --tag TAG | --folder ID) [--expect-rev REVISION] [--note TEXT]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<id>... | string | one of <id>, --tag or --folder | none | One or more scr_ screen ids. Several ids run as one fleet request. |
--tag TAG | string | one of <id>, --tag or --folder | none | Every active screen carrying this tag. |
--folder ID | string | one of <id>, --tag or --folder | none | Every active screen in this sfd_ screen folder and the folders inside it. |
--expect-rev REVISION | string | no | none | One screen id only. Optional revision precondition. |
--note TEXT | string | no | none | A note for the person who reviews the change: plain text, at most 280 characters. Ignored when the change applies at once. |
screenrig screen schedule clear --tag CafeThe takeover, else a campaign that holds, else the assigned playlist, is what plays afterwards. A screen without a schedule answers unchanged.
screen schedule preview#
Show what replacing a screen's playlist schedule would change, without making it.
screen schedule preview <id> --file FILE [--calendar-from INSTANT] [--calendar-to INSTANT]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<id> | string | yes | none | The scr_ screen id. |
--file FILE | path | yes | none | The schedule document as screen schedule set takes it, or - for stdin. The JSON of screen schedule show is accepted back. |
--calendar-from INSTANT | string | no | now | Start the calendars at this instant with a zone, such as 2026-12-01T00:00:00Z. |
--calendar-to INSTANT | string | no | a week after the start | End the calendars at this instant with a zone, at most 93 days after the start. |
screenrig screen schedule preview scr_LOBBY --file dayparts.json
screenrig screen schedule preview scr_LOBBY --file dayparts.json --calendar-from 2026-12-01T00:00:00Z --calendar-to 2027-01-01T00:00:00ZNothing is written. The entries are checked as screen schedule set checks them, so a preview refuses what the set refuses. data.gained and data.lost, each {count, screen_ids}, say whether the screen would gain or lose levels of its schedule; an entry with "paused": true is on no screen, so publishing one gains it. data.calendar.before and data.calendar.after are the screen's calendar as it is and as it would be over --calendar-from to --calendar-to.
screen schedule revisions#
List a screen's playlist schedule revisions, newest first.
screen schedule revisions <id> [--after CURSOR]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<id> | string | yes | none | The scr_ screen id. |
--after CURSOR | string | no | the first page | Continue from the data.next_cursor of the previous page. |
screenrig screen schedule revisions scr_LOBBY
screenrig screen schedule revisions scr_LOBBY --after CURSORdata.items holds at most 50 revisions, each with revision (the screen's revision at the write, so the numbers have gaps where the screen changed otherwise), created_at, change, current, author when known and entries, the whole schedule after that write (none means the screen had no schedule). change is edited (a set, a clear or a schedule import), restored (a copy of the earlier revision restored_from names) or baseline (the schedule the screen held when its history began). While data.next_cursor is a string, older revisions remain: run the command again with --after set to it. Revisions go with the screen's purge. Read only access is enough.
screen schedule restore#
Put an earlier revision's schedule back on a screen by copying it forward.
screen schedule restore <id> --revision N [--expect-rev REVISION] [--note TEXT]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<id> | string | yes | none | The scr_ screen id. |
--revision N | integer | yes | none | The revision to copy forward, as screen schedule revisions numbers it. |
--expect-rev REVISION | string | no | the revision just read | Require this current screen revision, not N. Without it the CLI reads the screen just before the write and sends that revision; a change in between is revision_conflict (exit 6). |
--note TEXT | string | no | none | A note for the person who reviews the change: plain text, at most 280 characters. Ignored when the change applies at once. |
screenrig screen schedule restore scr_LOBBY --revision 4
screenrig screen schedule restore scr_LOBBY --revision 4 --expect-rev 9Revision N's entries become the screen's schedule, the same write as screen schedule set with those entries (or screen schedule clear when that revision had none), checked as they are checked now: a playlist deleted since refuses it. Under Propose access, or in a project that requires review for agent changes, the restore waits for a person like the set does, and nothing changes on screen until they approve it. Earlier revisions stay as they were.
screen takeover#
Show one playlist on a screen or a fleet ahead of campaigns, the schedule and the assignment.
screen takeover [set] (<id>... | --tag TAG | --folder ID) --playlist-id ID [--until TIME | --for DURATION] [--reason TEXT] [--expect-rev REVISION] [--note TEXT]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<id>... | string | one of <id>, --tag or --folder | none | One or more scr_ screen ids. Several ids run as one fleet request. |
--tag TAG | string | one of <id>, --tag or --folder | none | Every active screen carrying this tag. |
--folder ID | string | one of <id>, --tag or --folder | none | Every active screen in this sfd_ screen folder and the folders inside it. |
--playlist-id ID | string | yes | none | The pl_ playlist to show. |
--until TIME | string | no | held until cleared | A strict RFC 3339 instant with seconds and an offset, in the form YYYY-MM-DDTHH:MM:SSZ or YYYY-MM-DDTHH:MM:SS-07:00, sent normalized to UTC; strictly in the future and at most 7 days ahead. Or none to hold until screen takeover clear. |
--for DURATION | string | no | held until cleared | 30m, 2h, or 3d, up to 6d23h59m, converted to an until from this computer's clock. 7d is refused locally; use --until for a full 7 days. Not with --until. |
--reason TEXT | string | no | none | An operator note on the takeover and its events. Trimmed, at most 120 characters, and no control characters. |
--expect-rev REVISION | string | no | none | One screen id only. Optional revision precondition. |
--note TEXT | string | no | none | A note for the person who reviews the change: plain text, at most 280 characters. Ignored when the change applies at once. |
screenrig screen takeover scr_LOBBY --playlist-id pl_DRILL --for 30m --reason "Fire drill"
screenrig screen takeover --tag Lobby --playlist-id pl_LAUNCH --for 2h
screenrig screen takeover --folder sfd_01EXAMPLEFOLDER000000000 --playlist-id pl_LAUNCH --for 2h
screenrig screen takeover scr_A scr_B --playlist-id pl_NOTICE --until nonescreen takeover ID is short for screen takeover set ID. A new takeover replaces the previous one, except the same playlist posted again while its takeover is in force with no --reason or the same one, which keeps that takeover and only moves its end. When it ends, the screen returns to a campaign that holds, its schedule or its assigned playlist on its own. A takeover whose playlist cannot be shown ends. A --for rerun after an ambiguous failure computes a new end and is sent as a new request.
screen takeover clear#
End the takeover on a screen or a fleet.
screen takeover clear (<id>... | --tag TAG | --folder ID) [--expect-rev REVISION] [--note TEXT]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<id>... | string | one of <id>, --tag or --folder | none | One or more scr_ screen ids. Several ids run as one fleet request. |
--tag TAG | string | one of <id>, --tag or --folder | none | Every active screen carrying this tag. |
--folder ID | string | one of <id>, --tag or --folder | none | Every active screen in this sfd_ screen folder and the folders inside it. |
--expect-rev REVISION | string | no | none | One screen id only. Optional revision precondition. |
--note TEXT | string | no | none | A note for the person who reviews the change: plain text, at most 280 characters. Ignored when the change applies at once. |
screenrig screen takeover clear --tag LobbyA campaign that holds, else the schedule, else the assigned playlist, is what plays afterwards. A screen without a takeover answers unchanged.
The schedule file
A schedule lists 1 to 32 entries in priority order; the first entry that holds wins. An entry names a playlist_id and sets at least one rule of a level: windows, monthly, dates, except, data, interaction, from or until, and optionally displays, covers, start and paused. windows has 1 to 16 items in the screen timezone: days uses mon to sun, and start and end are HH:MM; omit both for the whole day. An end at or before start crosses midnight and belongs to the start day. monthly has 1 to 16 items, and dates and except 1 to 100 each, an except date once only. The server refuses an except date outside from and until, a dates item that starts outside them, and a dates item that is also an except date. Optional from (inclusive) and until (exclusive) are civil minutes such as 2026-12-24T18:00, with no offset, and from is before until. covers is full (default), main, header, footer or side, displays lists 1 to 12 different outputs, and start is next_item (default) or on_time, as in the level rules above. An id is 1 to 64 letters, digits, - or _, used once; an omitted id becomes entry_N. An entry with "paused": true is a draft: it is on no screen's stack, screen schedule show marks it and the calendar draws it dashed. Send the schedule again without paused to publish it. The CLI checks this shape before sending anything. Breakfast, lunch, and dinner dayparts:
{
"entries": [
{ "id": "breakfast", "playlist_id": "pl_BREAKFAST",
"windows": [{ "days": ["mon", "tue", "wed", "thu", "fri"], "start": "06:00", "end": "11:00" },
{ "days": ["sat", "sun"], "start": "08:00", "end": "12:00" }] },
{ "id": "lunch", "playlist_id": "pl_LUNCH",
"windows": [{ "days": ["mon", "tue", "wed", "thu", "fri"], "start": "11:00", "end": "15:00" }] },
{ "id": "dinner", "playlist_id": "pl_DINNER",
"windows": [{ "days": ["mon", "tue", "wed", "thu", "fri", "sat", "sun"], "start": "17:00", "end": "22:00" }] }
]
}A menu that plays while someone uses the screen, above a first-Sunday brunch that skips one date:
{
"entries": [
{ "id": "browse", "playlist_id": "pl_MENU", "interaction": { "idle_s": 90 } },
{ "id": "brunch", "playlist_id": "pl_BRUNCH",
"monthly": [{ "nth": 1, "weekday": "sun", "start": "10:00", "end": "14:00" }],
"except": ["2026-12-06"] }
]
}A playlist schedule chooses between playlists; page visibility inside one playlist still chooses between its pages.
Schedule and takeover events
events list and events follow print screen.playlist_switched (playlist_id, previous_playlist_id, source, entry_id, until), screen.takeover_started (playlist_id, until, where none means held until cleared, and reason), screen.takeover_updated (playlist_id, until, previous_until and reason, where none means held until cleared: the same takeover given a new end), screen.takeover_ended (playlist_id, until when it had one, and reason expired, cleared, replaced, playlist_deleted, or playlist_unavailable), and the warning screen.playlist_unavailable (playlist_id, code playlist_deleted or playlist_unavailable, and the entry_ids, campaign_ids or folder_id that name the playlist).
Deleting a playlist fails with resource_conflict (exit 5) while a screen, archived ones included, has it assigned, named by a schedule entry, held by a takeover or effective, or while a campaign or a screen folder default names it. next points at screen list.
Schedule import
schedule import reads a sheet of schedule rows (screen, file, start, end), checks every row against the project, previews the levels it makes and the calendar effect, and with --commit applies all of it or none. schedule template saves a sheet to start from. Schedule import describes the columns, targets, times and row errors. A single screen's own schedule is screen schedule set, and a campaign schedules an audience.
Preview and commit belong to Premium and above: a plan without schedule import answers feature_not_in_plan (exit 8), and the template is open on every plan. Preview and commit are not available to a caller limited to screen folders (outside_screen_scope, exit 3).
schedule import#
Check a sheet of schedule rows and preview what it does; --commit applies it.
schedule import <file> [--name NAME] [--timezone ZONE] [--code-field FIELD] [--commit]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<file> | path | yes | none | A .csv (UTF-8), .xlsx (its first sheet) or .json sheet, or - to read JSON rows, CSV text or an XLSX workbook from standard input. A JSON sheet is an array of row objects or {"rows": [...]}, keyed by column name. At most 5,000 rows and 8 MiB. |
--name NAME | string | no | the file name without its extension | Name the import, 1 to 80 characters. Importing again under the same name updates the levels it made, removes the levels whose rows are gone and leaves an identical sheet unchanged. |
--timezone ZONE | string | no | each screen's own clock | The IANA zone, such as America/New_York, that a row's times are written in when the row has no timezone cell. |
--code-field FIELD | string | no | any field | Read a target's screen code only from this screen field, such as code or room_id. |
--commit | boolean | no | off | Apply the import when the preview is valid. With row errors nothing is written. |
screenrig schedule import schedule.csv
screenrig schedule import schedule.xlsx --name "Spring promos" --timezone America/Los_Angeles
screenrig schedule import schedule.csv --name "Spring promos" --commit
screenrig schedule import rows.json --code-field room_id
screenrig schedule import - --name "Spring promos" --commitWithout --commit nothing is written. data is the preview: valid, fingerprint, summary (rows, rows_with_errors, levels, creates, updates, unchanged, removes, screens, playlists), rows, levels, removals and calendar, ignored_columns for a column nothing reads, and next, the command that commits. Rows that agree on content, times, priority and name become one level: one screen is an entry of that screen's own schedule, and several screens, a folder or a tag are one shared level, a campaign that outranks a screen's own levels.
A valid sheet exits 0. Rows with errors exit 8 with data.valid false: data.rows[].errors names each cell's column and code, nothing is written, --commit commits nothing, and the same command runs again once the rows are corrected.
With --commit the run sends the preview's fingerprint and an idempotency key derived from the name and the fingerprint, so rerunning an interrupted identical command is safe. data is then the preview plus data.applied (creates, updates, unchanged, removes, screens, playlists) and data.committed true, and the one-file playlists the sheet's files need are made first. All rows apply or none does. A project that changed since the preview, or rows that read differently, is schedule_import_stale (exit 5): nothing was written, and the same command previews again. A commit that reaches a screen in a protected folder is refused whole with protected_target (exit 5), and one that updates or deletes a reserved campaign answers reserved_item (exit 3) unless a person who can approve commits it. Preview needs Read only access, and --commit needs Manage access. A file the CLI cannot read is a usage_error (exit 2).
schedule template#
Save a sheet with the columns a schedule import reads and three example rows.
schedule template [--format csv|xlsx] [--output FILE] [--overwrite]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
--format FORMAT | string | no | csv | csv or xlsx. |
--output FILE | path | for xlsx | print the CSV | Write the sheet to this file. Without it the CSV is printed and data.content holds it. |
--overwrite | boolean | no | off | Replace --output when it exists. It needs --output. |
screenrig schedule template
screenrig schedule template --output schedule.csv
screenrig schedule template --format xlsx --output schedule.xlsx --overwriteThe example rows are a screen code, a screen folder and a tag. With --output, data holds format, output, bytes and next, the schedule import command for the saved file. An existing non-empty --output file fails with usage_error (exit 2) and stays as it was unless --overwrite is passed. Fill one row per screen and file, then run schedule import FILE to preview it.