CLI
The screenci CLI keeps the workflow small: initialize a project, iterate
locally with screenci test, refine videos with screenci preview and the web
editor, export the finished videos with screenci export, and manage public
delivery when needed. Run
commands from inside your screenci/ project directory. Most commands resolve
screenci.config.ts from the current directory unless you pass
--config <path>.
Command overview
| Command | Purpose |
|---|---|
screenci setup <code> |
Set up a workspace from a setup code created in the web app |
screenci context |
Print what the agent knows about this project (site, sign-in, notes) |
screenci login [url] |
Sign in to your own app once and reuse that session in every recording |
screenci logout |
Forget the signed-in session saved on this machine |
screenci init [name] |
Scaffold a ScreenCI project |
screenci explore <url> |
Print compact page snapshots of a site, before and after clicks and fills |
screenci ci-workflow |
Write the GitHub Actions workflow that records the workspace from CI |
screenci test [playwrightArgs] |
Run .screenci.ts files locally without final recording |
screenci preview [pattern] |
Record live previews and print their links |
screenci export [patterns...] |
Produce finished videos: re-record every requested video, render, and download |
screenci info |
Print the last record run’s URLs and render status |
screenci make-public <videoId> |
Enable public delivery for a video |
screenci make-private <videoId> |
Disable public delivery for a video |
screenci delete <videoId> |
Permanently delete a video and its renders |
screenci setup <code>
The entry point of the web-app flow. The
Add project, Add video, Add screenshot, Edit, Add a
language, Re-record / Record all, and Add to CI buttons in the
app produce a prompt that carries a one-time setup code and points the agent
at the brief for that button (screenci.com/add-project.md,
/add-video.md, /add-screenshot.md, /edit-video.md, /add-language.md,
/record-video.md, or /add-to-ci.md); the coding agent runs the command in
the repository of the app to record, or in an empty folder:
npx screenci@latest setup SC-7K3Q-M9XAIt runs without a config file (there may be no workspace yet) and does the following:
- Exchanges the code for a project-scoped
SCREENCI_SECRETand writes it into the workspace’s env file. The secret only addresses that project. A code belongs to the first machine that exchanges it (rerunning there resumes it until a run lands; other machines are refused) and expires 24 hours after it was created. - Reads what the project knows (AI context: its site URL, whether it needs a sign-in, the notes for the agent) and locates the repository: the git checkout the command runs in, when there is one. Nothing is cloned; outside any repository the brief tells the agent to work from the site alone.
- Prepares the workspace. Inside a repository it is the island the
repository already holds for the project, wherever it sits (a monorepo
keeps it under a package; the config’s
projectId, or itsprojectNamefor an island made byscreenci init, says which project it belongs to), else the repository’sscreenci/; outside any repository,./screenci. Everypreviewandexportuploads the workspace’s text sources, and each version remembers the sources it was recorded from (see Source sync).- Absent, new project: scaffolds the workspace like
init --yes(agent skills on, no GitHub workflow) and writesprojectIdintoscreenci.config.ts. - Absent, existing project with sources on ScreenCI: pulls them, installs dependencies and the Playwright browser, and installs the agent skills at the repository root. A code made from a video page (Edit, Add a language, Re-record of one video) pulls the sources of the version the person was viewing, so any version can be the starting point of an edit; the project-level codes pull the project’s latest. Binary media is not pulled; recordings reuse the project’s uploaded assets.
- Absent, existing project without sources: scaffolds a fresh
workspace for it. A code that addresses one video refuses instead: its
script is only in the repository, so run the command there or pass
--dir. - Present, same
projectId, or noprojectIdand the same project name: used. For a code made from a video page, the version’s sources are the starting point: outside a repository, files that differ are replaced with the version’s and listed (every recording made there was uploaded, so earlier versions keep their own sources on ScreenCI); inside a repository, the repository’s scripts win and the brief lists the files in which the version differs (--forcereplaces them with the version’s, refused while the tree has uncommitted changes). An island that only names the project gets itsprojectIdwritten in. - Present, another project: refuses and proposes
--dir screenci-<project>. - Record code: nothing is changed; the brief names the script (for one video) and says whether a pipeline already records the project, in which case the agent triggers it instead of recording locally.
- CI code: mints a CI key (no person behind it, so its uploads show as
“CI”), needs the repository (the one the command runs in),
uses its
screenci/workspace (pulling the snapshot into it when the repository has none yet, for the agent to commit together with the pipeline), lists the CI providers whose files the repository has (.github/workflows,.gitlab-ci.yml,.circleci/config.yml,.buildkite,bitbucket-pipelines.yml,Jenkinsfile,azure-pipelines.yml), and prints a brief that stores the key in the provider’s secret store, adds the pipeline (ci-workflowfor GitHub Actions, the CI setup templates elsewhere), and triggers the first run. The site is not probed.
- Absent, new project: scaffolds the workspace like
- Looks for a signed-in session on this machine
(
.screenci/auth/default.json, saved bylogin) and reports it in the brief. Nothing about your own product’s credentials comes from, or goes to, ScreenCI. - Decides where to record. The scripts name an address (
webServer.urloruse.baseURLinscreenci.config.ts). When that is a dev server and this machine can run it (it already answers, or the command runs inside the repository and the agent may start the app), the recording goes there as usual. Otherwise the deployed site takes over: the prompt’s app URL, else the context’s site URL, else the site the chosen version was recorded against. The brief then tells the agent to point the scripts at it by hand:video.use({ baseURL })on the video it works on (the config and the other videos stay as they are), nowebServerblock for this run, and anypage.gotothat spells out the local address turned into a path relative to the base URL. It also says to check that the data the flow expects exists on the live site before recording, and to report a step that needs data rather than work around it. A teammate without the repository can therefore edit a video whose scripts an engineer pointed atlocalhost. The chosen address is probed; when nothing answers and nothing else is known, the brief says STOP and the command exits with code 2; see Running the app locally. - Prints a brief for the agent (the task, the starting point, the
repository, the site, how to sign in, the team’s notes, which script to
edit, the commands to run). With
--jsonit is followed by one machine-readable JSON line ({"status":"ready", ...}, or"stopped"with astopobject). The line also carriesvideoSourcePathand how it was found (videoSourceLocation:server,title,other-island,missing), thestartingPoint(the version and the files replaced or differing), and therecordingTarget(configured,overridewith the address to use, orstop).
Options:
--name <projectName>names a new project. Precedence: this flag, then the name typed in the web dialog, then the current folder name.--dir <path>uses another workspace folder than the onesetupwould pick (it wins over the island found in the repository, also for Add to CI).--forcereplaces an existing workspace of this project with the sources the code starts from (the chosen version’s, or the project’s latest); local files that differ are overwritten and listed. Refused inside a repository whose tree has uncommitted changes.--package-manager <npm|pnpm|yarn>overrides the auto-detected manager.--agent <name>targets a specific coding agent for the skills install.--skip-site-checkrecords even when the site does not answer.-v, --verboseprints underlying command output.
After setup, the usual commands run from inside the workspace: test,
preview, export. They upload the workspace’s text sources (see
Source sync) and report the finished run, which is what makes
the originating browser tab open the result. When the workspace lives in a
repository, the agent commits its change on a branch; that is the whole of
“keeping the videos in the repository”.
screenci context
Prints what the agent knows about the workspace’s project
(AI context: the site URL, whether the site needs
a sign-in, the team’s notes), whether a
signed-in session is saved on this machine, the
branding new videos start from, and one
JSON line (with a branding key). When the branding voice is cloned from a
sample, the sample is saved as branding/<file> in the workspace and the JSON
line names it as brandingSamplePath. The
shared branding assets are listed with
their kind and guide, saved as branding/<name>, and named in the JSON line as
brandingAssetPaths. Runs inside a workspace; uses SCREENCI_SECRET
from the env file. The session line is read from disk,
not from the service.
npx screenci contextnpx screenci context --json # the JSON line onlyscreenci login
Captures the signed-in session of your own app, so recordings start signed in and your video scripts contain no sign-in steps. It opens a real browser you sign in to yourself, which is why two-factor, single sign-on, passkeys, and magic links all work. See Signing In for the whole picture.
Run it from the screenci/ workspace. It needs no ScreenCI account and no
secret: an address is enough.
npx screenci login https://app.example.com # opens a browser, returns at oncenpx screenci login # uses use.baseURL from the confignpx screenci login --wait # blocks until you finish signing innpx screenci login --done # finish it now, from the terminalnpx screenci login --status # what is saved, and until whennpx screenci login --cancel # close it, save nothingThe command returns immediately so whoever started it can tell you to sign in. Finish by clicking I’m signed in on the small ScreenCI card floating over the page (drag it if it is in the way); closing the window finishes it too.
An agent then runs --wait, which blocks until you do, so your click actually
reaches it. Without that the agent has ended its turn and the click tells it
nothing. --wait gives up after eight minutes and says the sign-in is still
going, so it fits inside an agent’s command timeout and can simply be run
again. --done is the other direction: it finishes the sign-in right now, for
when you say you are done rather than clicking.
Options:
--profile <name>names the session, for a video that needs a second role. Pick it for a run withSCREENCI_AUTH_PROFILE=<name>.--timeout <minutes>closes the browser by itself after this long (default 30).-c, --config <path>points at anotherscreenci.config.ts.
The session is written to .screenci/auth/<profile>.json, owner-readable only
and gitignored, and screenci.config.ts picks it up automatically. It never
leaves the machine: ScreenCI stores no credential and no session for your app.
Nothing prints its contents, --status included.
On a machine with no display (a server, a container, CI) the command refuses and points at CI Setup, which is where an unattended session comes from.
screenci logout
Forgets the saved session on this machine.
npx screenci logoutnpx screenci logout --profile adminscreenci init
Create a new ScreenCI project in the current directory:
npm init screenci@latestpnpm --config.minimum-release-age-exclude=screenci --config.enable-global-virtual-store=false dlx screenci@latest initThe two --config flags are a temporary workaround for pnpm 11: it only installs versions published at least a day ago, and on Windows its global virtual store can link one-off (dlx) packages without their dependencies. They will be dropped once pnpm create screenci works under pnpm 11 again.
create-screenci and screenci init already turn the store off for the pnpm dlx commands they run.
yarn create screenciThe project name defaults to the repository root directory name.
AI agents pass --brief (npm init screenci@latest -- --yes --brief): the
starter example scripts are not written, and instead of the human next steps
the command prints a short authoring card (a script template, the rules, the
common edits, and the preview command).
Connecting to an existing account
No account or secret is needed to scaffold, record, or preview: without one,
preview uploads under a local, anonymous trial session and prints the web
preview link, then you sign up to keep it. Recording an anonymous trial agrees
to the Terms, which the CLI prints before it
starts. Exporting requires an account with an active paid subscription.
To connect the project to an account you already have, pass your
SCREENCI_SECRET (from your secrets page) as init’s positional argument, and
it writes the secret straight into screenci/.env:
npm init screenci@latest PASTE_YOUR_SCREENCI_SECRET_HEREYou can also skip this and copy SCREENCI_SECRET into screenci/.env by hand
at any point before recording.
When using npm init, pass extra initializer flags after --:
npm init screenci@latest -- --yes --package-manager pnpmnpm init screenci@latest -- --yes --package-manager yarnThe package manager is auto-detected from the npm_config_user_agent environment
variable (set automatically when you run pnpm create or yarn create), lockfile
presence (pnpm-lock.yaml, yarn.lock), or the packageManager field in
package.json. Use --package-manager to override.
To keep setup fast, init only prompts for the choices that genuinely vary:
the project name and whether to install AI agent skills (the ScreenCI skill
plus playwright-cli). Everything else is applied at a sensible default and
can be steered with a flag. init adds no CI pipeline: recording from CI is
a separate step, Add to CI in the web app or
ci-workflow.
Common options:
-y, --yesaccepts all defaults and skips every prompt--package-manager <npm|pnpm|yarn>overrides auto-detected package manager--agent <name>passes an agent name to the selected skills install command-v, --verboseprints underlying command output
Flags to override an auto-applied default without going interactive:
--github-workflowalso writes the GitHub Actions workflow (.github/workflows/screenci.yaml), the same fileci-workflowwrites--no-skillsskips both AI agent skills (and their prompt)--no-playwright-clikeeps the ScreenCI skill but dropsplaywright-cli(the skill and the@playwright/clidev dependency)--no-reactskips React overlay support (react/react-dom and JSX)--no-playwright-browsersskips installing the Chromium shell--playwright-os-depsinstalls Playwright operating system dependencies (off by default because it may require sudo)
Applied defaults: install dependencies, add React overlay support, install
the Chromium shell, skip OS dependency installation, install the AI agent
skills (ScreenCI + playwright-cli), and write no CI workflow.
The AI skills install is best effort: if it fails (for example on an older
Node.js runtime), init warns, prints the command to retry it later, and
continues with the rest of the setup.
Use this command in Manual Setup & First Video.
screenci explore <url>
Opens the recorder’s browser headless (with the config’s channel and the saved
sign-in session, when there is one), loads the page, and prints a compact
snapshot of its headings and interactive elements. --click <name> and
--fill <label>=<value> run in the order given, each followed by a new
snapshot; the final URL is printed last.
npx screenci explore https://app.example.com --click "Sales" --click "New lead"screenci ci-workflow
Writes the GitHub Actions workflow that records the repository’s screenci/
workspace from CI, at .github/workflows/screenci.yaml in the repository
root. Run it from the repository root (or inside the workspace, or with
--config <path>):
npx screenci ci-workflowThe workflow is keyed to the package manager the workspace uses (from its
lockfile; --package-manager <npm|pnpm|yarn> overrides it). An existing
file is never overwritten unless --force is given. The Add to CI brief
runs this for GitHub repositories; other providers follow the templates in
CI Setup. The secret still has to be
stored in the repository’s secrets: see Required secret.
screenci test [playwrightArgs...]
Run videos locally without the final recording pipeline:
npx screenci testnpx screenci test recordings/onboarding.screenci.tsnpx screenci test --grep "billing"npx screenci test --uipnpm exec screenci testpnpm exec screenci test recordings/onboarding.screenci.tspnpm exec screenci test --grep "billing"pnpm exec screenci test --uiyarn screenci testyarn screenci test recordings/onboarding.screenci.tsyarn screenci test --grep "billing"yarn screenci test --uiUse this during normal authoring. Most trailing arguments are forwarded to Playwright.
Plain screenci test disables recording-style waits so authoring runs stay
fast. That includes ScreenCI cursor/camera pauses and
page.waitForTimeout(...), which is collapsed to 0ms. Use Playwright locator
or load-state waits for real application readiness. Use --mock-record when you
need to preview the same pacing that a real recording will capture.
Common Playwright examples that also work here:
npx screenci test --project=chromiumnpx screenci test --grep "onboarding"npx screenci test --uipnpm exec screenci test --project=chromiumpnpm exec screenci test --grep "onboarding"pnpm exec screenci test --uiyarn screenci test --project=chromiumyarn screenci test --grep "onboarding"yarn screenci test --ui--mock-record
npx screenci test --mock-recordpnpm exec screenci test --mock-recordyarn screenci test --mock-recordThis keeps recording-like pacing enabled without starting the real recording
capture path. Use it when test passes but a real recording exposes timing
differences.
If you want that behavior by default for a project, set
test.mockRecord: true in screenci.config.ts.
screenci export [patterns...]
Produce finished videos and download them. export is the one-shot command
(CI runs preview by default and switches to export to publish on each
release): it pulls any queued editor edits into the sources,
re-records every requested video (sources can carry changes a hash check would
miss, so export always captures fresh footage), waits for the renders to
finish, and downloads the outputs into ./exports/:
npx screenci exportnpx screenci export "Onboarding"npx screenci export --grep "billing"npx screenci export --languages fi,enpnpm exec screenci exportpnpm exec screenci export "Onboarding"pnpm exec screenci export --grep "billing"pnpm exec screenci export --languages fi,enyarn screenci exportyarn screenci export "Onboarding"yarn screenci export --grep "billing"yarn screenci export --languages fi,enPositional arguments are title patterns (multiple are OR-combined, like
playwright test <pattern>); with no patterns, every video is exported in
every language. Downloads are named <title>.<lang>.mp4 (screenshots use
.png). The workspace’s sources are uploaded first (see
Source sync).
The command polls render status every 5 seconds for up to 30 minutes
and exits 0 only when every requested video rendered and downloaded. After a
run it prints the video’s page in the app: a run with exactly one rendered
pass links that video’s overview page with the run preselected
(<app>/project/<projectId>/video/<videoId>?export=<recordId>); several
passes (several videos, or one video exported in several languages) link the
run’s page (<app>/export/<recordId>), which links each version.
--languages <langs>
Export only specific language versions of videos declared with
video.languages([...]). Pass a comma-separated list:
npx screenci export --languages finpx screenci export --languages fi,enPer-language videos record and render only the requested languages, so a run
never produces more than you asked for. Videos that do not declare those
languages are skipped. A shared-mode recording ({ mode: 'shared' }) is a
single capture and is not split by this filter. See
Languages for the recording API.
-o, --output <dir>
Directory for the downloaded files. Defaults to exports:
npx screenci export -o dist/videos--no-wait
Start the renders and exit immediately, without waiting for them or downloading files. Use this when the finished videos are consumed from the web (public URLs or embeds) and the run only needs to publish fresh footage:
npx screenci export --no-waitThe command still records, uploads, and dispatches the renders, and prints
the results URL. It exits 0 as soon as the upload succeeds; render failures
are visible on the results page, not in the exit code. Without this flag,
export waits for every render and exits non-zero if any of them fails.
--share
Instead of downloading files, share each finished version with a permanent, version-pinned public URL and print the URLs:
npx screenci export --shareThe command records, renders, and waits like a normal export, then shares the run’s finished versions and prints one public URL per video and language (plus thumbnail and subtitle URLs when they exist). A shared version keeps serving that exact render until it is unshared or deleted from the app: it is exempt from version retention, and the URL works even when the video’s own public URL is switched off. See version-pinned URLs for the URL shape and behavior.
Shared versions count against your organization’s shared-version limit (1000 by default, shown on the billing page). When the limit is reached the remaining versions are not shared and the command exits non-zero with the refusal message.
--share needs finished renders, so combining it with --no-wait is an
error. It exits 0 only when every requested render finished and was shared.
--select
Make each finished render the served version of its language:
npx screenci export --selectWithout --select, an export never changes which version a video serves: the
public URL (and any video that embeds this one as a dependency) keeps pointing
at the version selected in the app until someone selects a newer one. With
--select, every render this run produces becomes the selected version of its
language as soon as it finishes, so a CI export updates the public URL on its
own. Selecting also re-renders dependent videos. Nothing is selected for
renders that fail.
The flag is never implied, in CI or elsewhere: pass it explicitly in the
workflow that should publish. The workflow screenci init generates shows it
on the commented export line.
--force
Deprecated no-op, kept so existing scripts do not break: export always
re-records every requested video.
Behavior:
- enables recording timing for every requested video
- writes local output into
.screenci/ - holds a per-project run lock at
.screenci/.record.lockwhile recording and uploading. If anotherscreenci previeworscreenci exportrun is already active, the second run exits non-zero instead of sharing the same.screencioutput. Stale locks are reclaimed automatically when the pid is gone or the lock is older than the maximum run TTL - requires an account with an active paid subscription: without a
SCREENCI_SECRET,exportrefuses before recording and prints a sign-up link (the anonymous trial is preview-only; usescreenci previewfor the free live preview, see Anonymous Trial). Once you have signed up, re-runningexportin the same folder links your account automatically. SetSCREENCI_SECRETfrom the project.env, the environment, or by runninginitwith it - uploads only the recordings requested by this run (for example the videos matched by patterns,
--grep, or--languages), with or withoutSCREENCI_SECRET - exits non-zero unless every requested video rendered and downloaded. If a requested video is missing its
recording.mp4or another failure occurs,exportdoes not save.screenci/last-record.jsonand does not print a success URL for unrelated output - prints any informational notices returned by the service in cyan after upload (occasional, non-error status messages such as maintenance or timing notes). These never affect the exit code
- new accounts choose a plan before exporting: exports need an active paid plan. Higher tiers raise export and active-video limits and unlock multiple languages
Relevant options:
-c, --config <path>-v, --verbose-g, --grep <pattern>(same filter as Playwright’s--grep)
Important restriction:
--retriesis not supported because ScreenCI forces retries to0
screenci preview [pattern]
Records live previews and prints their links: it re-records and uploads the
live preview of every matched video (all declared videos when no pattern is
given), prints the link, and exits. A preview always records fresh footage;
there is no freshness skip. A run with exactly one
recording pass prints that video’s overview page
(<app>/project/<projectId>/video/<videoId>); several passes (several
videos, or one video recorded in several languages) print the run listing
page (<app>/preview/<recordId>), which links each video and language.
screenci previewFilter videos by passing a title pattern, the same way
playwright test <pattern> does; --grep does the same and takes precedence
when both are given.
screenci preview "Auto-zoom"Right before recording a preview, the CLI sends a best-effort “preview recording started” notice to the backend, so an open web preview page shows a live “Recording preview…” indicator and refreshes automatically when the new preview lands.
preview runs the script itself, so no separate test run is needed first.
When the script fails, preview prints the error, exits with code 1, and
prints no link: fix the script and rerun it.
Source sync
preview and export upload the island’s text sources right before
recording (unless screenci.config.ts sets uploadSources: false), and
report the finished run afterwards. Every version remembers the sources it
was recorded from: that is what the video page shows under “Sources”, what
screenci setup pulls onto a machine without a workspace, and what an Edit
or Re-record prompt made from a version page starts from.
- The bundle holds
screenci.config.ts,package.json,tsconfig.json,.prettierrc,.gitignore,README.md, the package-manager workspace files, and every text file underrecordings/. Env files, lockfiles,node_modules,.screenci,exports, and binary media are never included. Files over 256 KB and anything past 2 MB in total are skipped with a warning. - The bundle is content addressed: an unchanged island is not re-uploaded.
Its canonical form is
{ "files": [{ "path", "content" }] }sorted by path (plain code-unit order), hashed with SHA-256 over the JSON text. - Both steps are best effort. A failed upload warns and the recording still runs (the next run retries); the run report never fails a command.
- Anonymous previews (no
SCREENCI_SECRET) never sync sources. - A project-scoped secret that pins a different project than the island’s
projectId(an env file copied from another workspace) stops the run before recording, with the pinned project’s name in the message.
A run prints one line per phase: the record announcement, the upload results, one line per video whose editor-uploaded media (overlays, audio, narration audio, cloned voices) shapes the render, and the video link:
Recording: Search for Alfa Forni Moderno 2...✔ Uploaded "Search for Alfa Forni Moderno 2 [en]"✔ Uploaded "Search for Alfa Forni Moderno 2 [et]"Editor-uploaded media for "Search for Alfa Forni Moderno 2" applies at render time; recordings always run from code.
Open the live preview for "Search for Alfa Forni Moderno 2" at:<app>/project/<projectId>/video/<videoId>Options:
-c, --config <path>: path to the ScreenCI config file.-g, --grep <pattern>: only manage videos whose title matches this pattern (the same filter as Playwright’s--grep, and the same as a positional pattern above). The record pass is limited to the matching videos.-v, --verbose: verbose output.
Setup (with an account): none beyond SCREENCI_SECRET. That secret is the
only credential ScreenCI needs; there is nothing else to paste.
Without an account, no setup is needed either: screenci preview runs under a
local, anonymous trial session (see
Anonymous Trial). Signing up claims the trial,
and the next screenci command picks up your new SCREENCI_SECRET (written
into screenci/.env).
screenci info
npx screenci infopnpm exec screenci infoyarn screenci infoLists every video in the project with its public URLs as JSON, keyed by
video name and language code. It is where you get the remote videoId for
make-public, make-private, and delete.
When this machine has recorded a successful run, info also reports that run.
Each screenci export upload stores its unique record id in
.screenci/last-record.json; info then attaches, only to the videos
produced by that run, a per-language latestRecord with the run’s render
status and its record-pinned URLs, plus a latestRecordId on the video. Videos
that were not part of the run are still listed, with static URLs only. This is
the command to use in CI to gate on rendering or grab links right after an
export.
{ "projectName": "My Product", "videos": { "Onboarding": { "videoId": "kh74…", "latestRecordId": "5f1c…", "isPublic": true, "languages": { "en": { "static": { "video": "https://api.screenci.com/public/kh74…/en/video", "thumbnail": "https://api.screenci.com/public/kh74…/en/thumbnail", "subtitle": "https://api.screenci.com/public/kh74…/en/subtitle", "screenshot": "https://api.screenci.com/public/kh74…/en/screenshot" }, "download": { "video": "https://api.screenci.com/cli/download/kh74…/en/video", "thumbnail": "https://api.screenci.com/cli/download/kh74…/en/thumbnail", "subtitle": "https://api.screenci.com/cli/download/kh74…/en/subtitle", "screenshot": "https://api.screenci.com/cli/download/kh74…/en/screenshot" }, "latestRecord": { "status": "finished", "video": "https://api.screenci.com/public/kh74…/records/5f1c…/en/video", "thumbnail": "https://api.screenci.com/public/kh74…/records/5f1c…/en/thumbnail", "subtitle": "https://api.screenci.com/public/kh74…/records/5f1c…/en/subtitle", "screenshot": "https://api.screenci.com/public/kh74…/records/5f1c…/en/screenshot", "download": { "video": "https://api.screenci.com/cli/download/kh74…/records/5f1c…/en/video", "thumbnail": "https://api.screenci.com/cli/download/kh74…/records/5f1c…/en/thumbnail", "subtitle": "https://api.screenci.com/cli/download/kh74…/records/5f1c…/en/subtitle", "screenshot": "https://api.screenci.com/cli/download/kh74…/records/5f1c…/en/screenshot" } } } } } }}Each language exposes up to three URL sets:
static: stable, public URLs that always follow the currently selected versiondownload: authenticated download URLs for the selected version (see below)latestRecord: this run’s render status plus public URLs pinned to it via arecords/<recordId>path segment (an immutable contract: the exact run, or404, see resolution rules). Once finished, it also carries record-pinneddownloadURLs.
Each URL set carries one entry per asset: video, thumbnail, subtitle, and
screenshot. A version is either a video or a screenshot, never both, so use the
video asset for video recordings and the screenshot asset for screenshot
recordings: the asset that does not match the version’s type 404s when fetched.
static is null for videos without public delivery enabled. latestRecord
carries the render status even for private videos, but its public URLs are then
null.
The download URLs are private: they require your X-ScreenCI-Secret
header, so they are not embeddable, and they work even for private videos. Use
them to archive a render permanently, before older versions are pruned (see
Keep a render forever):
curl -H "X-ScreenCI-Secret: $SCREENCI_SECRET" \ "https://api.screenci.com/cli/download/kh74…/records/5f1c…/en/video" \ -o video.mp4Render status (under latestRecord.status) is one of:
finished: a render finished and is servablerendering: a render is still in progress (or has not started)failed: a render failed and none for that language is still in progress
Because rendering happens after upload, poll info until each latestRecord
reaches finished (or gate your pipeline on failed).
Not recorded on this machine? If there is no .screenci/last-record.json
(for example a fresh checkout that has never run screenci export), info does
not fail. It simply omits latestRecordId and the latestRecord fields and
prints the project-wide listing with static URLs only.
screenci make-public <videoId>
npx screenci make-public kh74…pnpm exec screenci make-public kh74…yarn screenci make-public kh74…Enables public delivery for a video. Get the ID from screenci info.
When you make a video public, ScreenCI starts it in the same mode as the app:
- public delivery is enabled for the video
- the latest finished render for each language becomes the active public output
(later exports change it only with
export --selector a selection in the app)
That means make-public is the CLI equivalent of turning on Enable public
URL in the dashboard.
screenci make-private <videoId>
npx screenci make-private kh74…pnpm exec screenci make-private kh74…yarn screenci make-private kh74…Disables public delivery for a video.
This is the CLI equivalent of turning off Enable public URL in the dashboard.
screenci delete <videoId>
npx screenci delete kh74…pnpm exec screenci delete kh74…yarn screenci delete kh74…Permanently deletes a video and all of its renders. Use the same videoId that
make-public and make-private accept (copy it from screenci info).
This is irreversible, so the command prints the video’s name and asks you to
confirm before deleting. Pass -y (or --yes) to skip the prompt in CI or
scripts:
npx screenci delete kh74… --yesYou can only delete videos that belong to your own project’s organization.
What the CLI does not do
The CLI currently covers:
- workspace setup from a web-app setup code with
setup - reading what the project knows about itself with
context - signing in to your own app with
loginandlogout - project scaffolding with
init - project auth setup (handled automatically on first
export) - local iteration with
test - live previews and editing sessions with
preview - finished videos with
export - per-run URLs and render status with
info - public visibility changes with
make-publicandmake-private - permanent video deletion with
delete
Version selection happens in two places:
screenci export --selectselects each render this run produces as it finishes- in the app, open a language section and choose the version to mark as Selected
A selected version that is served at a public URL cannot be deleted until another version is selected or the public URL is switched off.
Shared environment and config behavior
These commands support --config <path>:
contextloginlogouttestpreviewexportinfomake-publicmake-privatedelete
SCREENCI_SECRET is used for:
- auth bootstrap and persistence
- uploads
- per-run URLs and render status (
info) - public delivery changes
- video deletion (
delete)
If envFile is configured in screenci.config.ts, the CLI loads it
automatically. Otherwise it falls back to the project .env. The CLI resolves
envFile by evaluating the config the same way Playwright does, so a dynamic
value like envFile: isLocal ? '.env.local' : '.env' picks the right file at
run time.
That env file is the recommended place to keep SCREENCI_SECRET and other
runtime variables your setup needs. Your ElevenLabs key is not kept here: add it
on the Branding page in the app instead (see
Narration).
Related pages
- Configuration for
screenci.config.ts.