CLI
The screenci CLI keeps the workflow small: initialize a project, iterate
locally, record final output, 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 init [name] | Scaffold a ScreenCI project |
screenci test [playwrightArgs] | Run .screenci.ts files locally without final recording |
screenci record [playwrightArgs] | Record videos and upload results when configured |
screenci info | Print the last record run’s URLs and render status |
screenci status | Compare Editor action edits with the latest recorded run |
screenci sync-prompt | Print an agent prompt to sync code with Editor edits |
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 init
Create a new ScreenCI project in the current directory:
npm init screenci@latestpnpm create screenciyarn create screenciThe project name defaults to the repository root directory name.
Connecting to an existing account
No account or secret is needed to scaffold or record: without one, record
uploads under a local, anonymous trial session and prints a link to view the
result, then you sign up to keep it. Recording an anonymous trial agrees to the
Terms, which record prints before it starts.
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, whether to add the GitHub Actions workflow, 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.
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:
--no-github-workflowskips the GitHub Actions workflow (and its prompt)--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: create the GitHub Actions workflow, install dependencies,
add React overlay support, install the Chromium shell, skip OS dependency
installation, and install the AI agent skills (ScreenCI + playwright-cli).
Use this command in Manual Setup & First Video.
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 screenci record 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 record exposes timing
differences.
If you want that behavior by default for a project, set
test.mockRecord: true in screenci.config.ts.
screenci record [playwrightArgs...]
Record final output:
npx screenci recordnpx screenci record recordings/onboarding.screenci.tsnpx screenci record --grep "billing"npx screenci record --project=chromiumpnpm exec screenci recordpnpm exec screenci record recordings/onboarding.screenci.tspnpm exec screenci record --grep "billing"pnpm exec screenci record --project=chromiumyarn screenci recordyarn screenci record recordings/onboarding.screenci.tsyarn screenci record --grep "billing"yarn screenci record --project=chromiumrecord forwards normal Playwright file filters and --grep, so you can limit
recording to only some videos just like with screenci test.
--languages <langs>
Record (and render) only specific language versions of videos declared with
video.languages([...]). Pass a comma-separated list:
npx screenci record --languages finpx screenci record --languages fi,enPer-language videos record 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.
--fast-narration
Skip narration-length pacing while recording. By default a per-language recording sleeps each cue’s real audio length so the recording matches the finished video (see How recording pacing works). With this flag the recording keeps only a short gap per cue and finishes as fast as the interactions allow; the render freezes a frame for the remaining audio instead:
npx screenci record --fast-narrationBehavior:
- enables recording timing
- writes local output into
.screenci/ - holds a per-project run lock at
.screenci/.record.lockwhile recording and uploading. If anotherscreenci recordis 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 - needs no
SCREENCI_SECRETto run: without one, it uploads under a local, anonymous trial session and prints a link to view the result. Recording an anonymous trial agrees to the Terms, whichrecordprints before it starts. To upload straight to your organization instead, setSCREENCI_SECRET(from the project.env, the environment, or by runninginitwith it) before recording - gives an anonymous trial exactly one recording. Once that first recording is used (or the trial expires), a second
screenci recordstops before it starts and prints a sign-up link instead of recording again, so no time is spent rendering a video that would only be refused. Sign up to keep recording; once you have, re-runningrecordin the same folder links your account automatically and uploads normally. The trial previews expressive narration and up to 3 languages at once; see Anonymous Trial for its full limits and what happens to that content after signup - uploads only the recordings requested by this run (for example the videos matched by
--grepor--languages), with or withoutSCREENCI_SECRET - prints a results URL only when the requested recordings uploaded successfully. If a requested video is missing its
recording.mp4or another upload failure occurs,recordexits non-zero, does not save.screenci/last-record.json, and 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 start on the Free plan automatically (no plan selection step). Free renders include a ScreenCI watermark; paid plans remove it and raise render and active-video limits, and unlock multiple languages plus expressive tone control
Relevant options:
-c, --config <path>-v, --verbose--remote(trigger the project’s GitHub Actions recording workflow instead of recording locally, see below)
Important restriction:
--retriesis not supported because ScreenCI forces retries to0
--remote
screenci record --remote does not record on your machine. Instead it asks
ScreenCI to dispatch the project’s GitHub Actions recording workflow, so the
recording runs in CI on demand. The project is resolved the same way as every
other command, from SCREENCI_SECRET and the config projectName, and exits as
soon as the workflow has been triggered.
npx screenci record --remotePass --grep to record only matching videos or screenshots remotely (the filter
is forwarded to the workflow’s grep input):
npx screenci record --remote --grep "Onboarding"This requires connecting the GitHub App to the project first (a one-time setup on
the project page in the app, see
Trigger recordings remotely).
Without a connected repository the command reports that GitHub is not connected.
Targeted (--grep) runs need the workflow to declare a grep input; projects
scaffolded by screenci init include it.
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 record 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 a record.
{ "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 record), info does
not fail. It simply omits latestRecordId and the latestRecord fields and
prints the project-wide listing with static URLs only.
screenci status
Fetches the web Editor’s current action-parameter edits and compares them with
the latest recorded run’s snapshot (.screenci/action-params.json). Reports
per video which overrides shadow explicitly code-set values, which change
defaulted values, which match code (no effect), and which are stale because the
action no longer exists in the latest recording.
Options:
-c, --config <path>: path toscreenci.config.ts-g, --grep <regex>: only include videos whose name matches the regular expression (same semantics as Playwright’s--grep)
Requires SCREENCI_SECRET. See
Action parameter tracking and overrides
for the full model.
screenci sync-prompt
Prints an agent-ready prompt that describes which action options to change or
remove in your .screenci.ts scripts so code matches the web Editor’s edits:
CHANGE items give the from/to values per locator and call, REMOVE items say
which explicit option to drop because the Editor reset it to the default, and
stale overrides are surfaced as warnings. Paste the output to a coding agent,
apply the edits, then re-record; once code and Editor agree the overrides can
be cleared.
Takes the same -c, --config and -g, --grep options as screenci status.
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
- auto-select latest is enabled
- the latest finished render for each language becomes the active public output
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:
- project scaffolding with
init - project auth setup (handled automatically on first
record) - local iteration with
test - final capture and upload with
record - per-run URLs and render status with
info - public visibility changes with
make-publicandmake-private - permanent video deletion with
delete
Manual version pinning is currently handled in the app UI:
- turn off Auto-select latest version
- open a language section
- choose the version to mark as Selected
Shared environment and config behavior
These commands support --config <path>:
testrecordinfomake-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 Secrets page in the app instead (see
Narration).
Related pages
- Configuration for
screenci.config.ts.