# Schedules CLI commands

> Canonical HTML: https://screenrig.ai/docs/cli/schedules

Set, preview, restore and clear a screen's playlist schedule, take screens over for a while and import schedules from a sheet. Every command here runs as described in the [CLI reference](https://screenrig.ai/docs/cli.md): global flags, JSON output, exit codes, revisions and retries.

## 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](https://screenrig.ai/docs/cli/campaigns.md#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](https://screenrig.ai/docs/cli/screens.md#screen-folders) 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](https://screenrig.ai/docs/schedule-import.md).

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](https://screenrig.ai/docs/players.md#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](https://screenrig.ai/pricing.md) 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](https://screenrig.ai/docs/cli/screens.md#screen-folders) and in every folder inside it) run as one [fleet request](https://screenrig.ai/docs/cli/screens.md#fleet-results) 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](https://screenrig.ai/docs/cli/reviews.md#reviews). On a screen in a [protected folder](https://screenrig.ai/docs/permissions.md#protected-folders) 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.

```console
screen schedule show <id>
```

| Parameter | Type | Required | Default | Notes |
| --- | --- | --- | --- | --- |
| `<id>` | string | yes | none | The `scr_` screen id. |

```console
screenrig screen schedule show scr_CAFE
```

`data` 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.

```console
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. |

```console
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.json
```

Every 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.

```console
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. |

```console
screenrig screen schedule clear --tag Cafe
```

The 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.

```console
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. |

```console
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:00Z
```

Nothing 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.

```console
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. |

```console
screenrig screen schedule revisions scr_LOBBY
screenrig screen schedule revisions scr_LOBBY --after CURSOR
```

`data.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.

```console
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. |

```console
screenrig screen schedule restore scr_LOBBY --revision 4
screenrig screen schedule restore scr_LOBBY --revision 4 --expect-rev 9
```

Revision `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.

```console
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. |

```console
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 none
```

`screen 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.

```console
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. |

```console
screenrig screen takeover clear --tag Lobby
```

A 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](https://screenrig.ai/docs/cli/schedules.md#schedules): `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:

```json
{
  "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:

```json
{
  "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](https://screenrig.ai/docs/schedule-import.md) describes the columns, targets, times and row errors. A single screen's own schedule is `screen schedule set`, and a [campaign](https://screenrig.ai/docs/cli/campaigns.md#campaigns) 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.

```console
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. |

```console
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" --commit
```

Without `--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.

```console
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`. |

```console
screenrig schedule template
screenrig schedule template --output schedule.csv
screenrig schedule template --format xlsx --output schedule.xlsx --overwrite
```

The 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.

<a id="reviews"></a>

## Other command groups

- [Projects](https://screenrig.ai/docs/cli/projects.md)
- [Service clients](https://screenrig.ai/docs/cli/service-clients.md)
- [Help and support](https://screenrig.ai/docs/cli/help.md)
- [Media](https://screenrig.ai/docs/cli/media.md)
- [Media sync](https://screenrig.ai/docs/cli/media-sync.md)
- [Playlists](https://screenrig.ai/docs/cli/playlists.md)
- [Cards](https://screenrig.ai/docs/cli/cards.md)
- [Applications](https://screenrig.ai/docs/cli/applications.md)
- [Screens](https://screenrig.ai/docs/cli/screens.md)
- [Campaigns](https://screenrig.ai/docs/cli/campaigns.md)
- [Device health](https://screenrig.ai/docs/cli/device.md)
- [Reviews and notes](https://screenrig.ai/docs/cli/reviews.md)
- [Notifications](https://screenrig.ai/docs/cli/notifications.md)
- [Reports](https://screenrig.ai/docs/cli/reports.md)
- [Data sources](https://screenrig.ai/docs/cli/data-sources.md)
- [BI dashboards](https://screenrig.ai/docs/cli/bi.md)
- [Triggers](https://screenrig.ai/docs/cli/triggers.md)
- [Fleet links](https://screenrig.ai/docs/cli/fleet-links.md)
- [Advertising](https://screenrig.ai/docs/cli/ads.md)
