About shotstack
A skill that guides terminal-based AI agents in using the Shotstack CLI to create, inspect, preview, and render video edits. It distinguishes local validation and browser previews from API-backed operations that require an API key.
Key features
- 01Validate Edit JSON offline
- 02Preview edits in Studio
- 03Inspect frames in a contact sheet
- 04Render video through the API
- 05Upload and host media files
- 06Generate assets and analyze music
Use cases
- 01Checking an edit before rendering
- 02Sharing an edit for human review
- 03Rendering a final MP4 in the cloud
- 04Hosting local media for an edit
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ shotstack/ shotstack-cli --skill shotstackAfter installing, type/shotstackin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
references/asset-library.mdbeat-sync.mdcaption.mdfonts.mdgeneration.mdhtml5-effects.mdhtml5-snippets.mdhtml5.mdingest.mdmotion.mdonboarding.mdpositioning.mdsvg.mdtimeline.mdtroubleshooting.mdshared/agent-core.mdDetails
From the project READMEShotstack CLI
This skill loads in terminal-based AI agents (Claude Code, Cursor, Codex CLI, Gemini CLI, etc.). All operations here are shell commands. There is no embedded UI, no iframe, no inline canvas, no MCP tool surface — only shotstack invocations from a terminal. To hand off to a human, run shotstack studio <file>; this opens the user's default browser to a shotstack.studio URL. Tell the user to click Render in the browser tab, not in any UI inside the terminal.
Check versions once per session
This skill is version 0.16.1 and needs @shotstack/cli 0.16.0 or later. Before the first shotstack command in a session:
- Run
shotstack --version. If it is older than 0.16.0, tell the user: what this skill documents, such asinspect, is missing until they runnpm install -g @shotstack/cli@latest. - Run
npm view @shotstack/cli version. If it is newer than this skill's version, tell the user an update is available and ask whether to install it. Only on a yes, runnpx skills update shotstack -yandnpm install -g @shotstack/cli@latest. Never update without asking.npx skills checkis not a read-only check: it installs the update.
If a check fails (no network, no npm, a sandbox), skip it and carry on.
Open-ended first render? Ask before composing. If the ask doesn't state what the video is (subject, format or destination) — e.g. "render my first video", "make me a video", "set up Shotstack" — read references/onboarding.md and ask its discovery questions, then WAIT for answers. Do not write an Edit first. An open-ended ask is not a specification, and a stray JSON file in the project doesn't make the user experienced. Compose without asking only when the user has stated what the video is, or explicitly says to just show anything.
Commands for the Shotstack video rendering API. render submits an Edit JSON and returns a render ID; status polls a render until done. ingest uploads your own local files (or fetches remote URLs) and hosts them so they can be referenced from an Edit. validate lints an Edit — run it before every render. studio opens an edit in the browser editor for a human to preview, tweak, and render. inspect draws an edit's frames, or a render's or a video's, at the times you give into one contact sheet, in headless Chrome, so you can look at your own work without rendering. template list|get|create|update|delete reads and writes templates saved to the account: list shows saved templates (id + name); get <id> fetches a saved template's Edit JSON (e.g. one the user designed in Studio) so you can render or remix it; create <file> --name <name> saves an edit as a new template; update <id> <file> overwrites one; delete <id> removes one. models lists the generation models for prompt-driven assets and whether this key can use each one; models <id> prints the options a model accepts. generate <model> "<prompt>" generates one asset on its own and prints its URL. analyze <url> measures a music track's tempo, beats, bars, drops and sections, free, and needs an API key.
Default loop — no API key required: compose → validate (offline lint) → inspect (look at the frames yourself) → studio (browser preview for the human). Only the API-backed commands (render, status, ingest, models, generate, analyze) need a key. Reach for render when you specifically need a final MP4 exported in the cloud; reach for studio for everything else — it is the cheapest way to see an edit and the right default for any creative a human will review.
Authentication
Save your API key once with shotstack login — it's stored in ~/.shotstack/credentials.json (chmod 600), per environment, so you don't re-enter it every session:
shotstack login # prompts (hidden input); saves the v1 (production) key
shotstack login --env stage # save the stage key (Shotstack keys are env-specific)
echo "$KEY" | shotstack login # non-interactive (CI / agents): read the key from stdin
shotstack logout --env stage # forget one env; shotstack logout --all forgets all
Or set an environment variable (overrides the saved key — best for CI):
export SHOTSTACK_API_KEY=...
Resolution precedence: SHOTSTACK_API_KEY env var → saved key for the target --env → error. Get a key at https://app.shotstack.io. validate and studio need no key — only the API-backed commands (render, status, ingest, models, generate, analyze) require one; without a key those exit 1, while compose → validate → studio keeps working.
Environments
--env stage → https://api.shotstack.io/edit/stage (test credits, free)
--env v1 → https://api.shotstack.io/edit/v1 (production, default)
The cheapest iteration path is studio — not stage. studio previews client-side in the browser with no key and no credits (see the Studio section below); iterate there. --env stage gives a free cloud render (With watermark) for when you need a rendered video for review; v1 charges real credits. Override the target with the SHOTSTACK_ENV env var for the session. ingest commands hit the parallel …/ingest/{env} base automatically using the same key.
Quickstart
# 1 — Validate offline. Schema + same-track overlaps + fonts + URLs. No key, no credits.
shotstack validate template.json
# 2 — Preview in the browser. The DEFAULT next step: no key, no credits; a human hits Render.
shotstack studio template.json
# → opens https://shotstack.studio/s/<slug> and prints the short URL
# 3 — Export to MP4. Needs an API key and charges credits. Submit + poll in one command.
shotstack render template.json --watch
# → done https://shotstack-api-v1-output.s3.amazonaws.com/.../01ja7-x8m2k-39rzv-cmvxve.mp4
# Poll an existing render to a terminal state.
shotstack status 01ja7-x8m2k-39rzv-cmvxve --watch
# → done https://shotstack-api-v1-output.s3.amazonaws.com/.../01ja7-x8m2k-39rzv-cmvxve.mp4
Uploading local files to use in an Edit
An Edit can only reference media by URL — a local path in an asset.src will not render. To use a local file, host it first with shotstack ingest upload, then put the returned URL in your Edit.
# Upload a local file and poll until it's hosted. --watch prints the URL.
shotstack ingest upload ./clip.mp4 --watch --output json
# → {"id":"zzytey4v-...","status":"importing"}
# → {"id":"zzytey4v-...","status":"ready","source":"https://shotstack-ingest-api-v1-sources.s3...amazonaws.com/.../source.mp4",...}
# Capture the hosted URL straight into a variable:
SRC=$(shotstack ingest upload ./clip.mp4 --watch --output json | tail -n1 | jq -r .source)
# …then reference "$SRC" as an asset.src in your Edit JSON and run `shotstack render`.
This includes images and fonts for an html5 page: put the URL in its html or css.
The bare command (no --watch) returns only an id; the hosted source URL does not exist until ingestion is ready. Always --watch (or follow up with shotstack ingest status <id> --watch) when you need the URL.
Other ingest subcommands: ingest fetch <url> (host a copy of a remote URL), ingest status <id>, ingest list, ingest delete <id>. Read references/ingest.md for the full upload→render workflow, status values, and supported file types.
Generating assets
An image, video or audio asset with a prompt and a model is generated by AI. shotstack models lists the models and whether this API key can use each one. shotstack models <id> adds the JSON Schema for that model's options. Read it before setting options, because values outside it are rejected.
shotstack models --output json
shotstack models seedance-2.0-text-to-video --output json
Offer only models marked available. unavailable: AiCapabilityNotIncluded means the plan doesn't include that kind of generation, AiDisabled means AI is turned off for the account, and AiAccessUnavailable means access couldn't be confirmed, so try again later. "availability unknown" means the check didn't run. It is not a yes.
shotstack generate <model> "<prompt>" generates one asset without rendering an edit and prints its URL. Use it to try a prompt, a voice or a still before building it into a timeline. Inside an edit, set prompt and model on the asset instead and it is generated at render time.
shotstack generate nano-banana-2 "A ceramic mug on a walnut desk, soft window light" \
--options '{"resolution":"2K","aspectRatio":"16:9"}' --watch --output json | tail -n1 | jq -r .url
shotstack generate seedance-2.0-text-to-video "Waves break over black sand at dusk" --length 5 --watch
--length is the clip length in seconds. Models that generate to a duration use it in place of their own duration option.
Generation costs credits on stage as well as v1. Before generating, run the same command with --quote, tell the user the model and the credits it prints (it says "up to" when the final charge can be lower), and wait for a yes. Identical requests share one job and its cached result: repeating a request while it runs, or after it finishes, returns the same job without charging again. That is also how to pick up a job started without --watch. Sending a failed generation again retries it, and that is charged.
Cutting or animating to music? Measure the track with shotstack analyze <url> --output json and follow references/beat-sync.md: write every cut and keyframe in bars from the map, never from the BPM you asked for.
Read references/generation.md before writing a prompt. It covers what each model responds to, when to put text in a rich-text layer instead of the image, and how to size and chain generations inside an edit.
Default workflow: preview in Studio (no key, no credits)
shotstack studio <file> is the default way to look at an edit — prefer it over render unless you specifically need a cloud-exported MP4. It posts the JSON to https://shotstack.studio and opens https://shotstack.studio/s/<slug> in the browser — a short, shareable URL. No render credits charged; it previews client-side, so it works with no key (a key only makes the short link permanent). The human plays, edits, and decides whether to spend credits on a render.
shotstack studio template.json # opens browser + prints short URL
shotstack studio template.json --no-open # headless: just print the URL
shotstack studio template.json --no-shorten # emit base64url URL inline (offline / debug)
shotstack studio template.json --env stage # share with the saved stage key
shotstack studio template.json --output json # piping: {"url":"...","shortened":true}, no browser
On headless systems (no xdg-open, no $DISPLAY) the browser launch silently no-ops; the URL is still printed. Safe to run anywhere.
The short link is permanent when the CLI has an API key (SHOTSTACK_API_KEY, or the key saved for --env/SHOTSTACK_ENV). Without one it lasts 30 days and the command says so on stderr; suggest shotstack login if the user wants links that last. A timeout, 429 or 5xx gets one retry, then the command falls back to the inline base64url form and prints the cause on stderr. If the share API refuses the edit (over 1 MB, missing timeline or output, or an invalid key), the command exits 1 with the reason: fix that, or use --no-shorten.
Default to studio for anything non-trivial — multi-scene, multi-track, or any creative an interested human will review. It previews client-side, costs nothing, and lets the human hit Render when it's right. Use render directly only for single-shot/simple edits, automated pipelines, or when told "just render it".
Check frames with inspect (no key, no credits)
shotstack inspect loads the edit into Studio in headless Chrome and writes the frames at your times into one image, each tile labelled with its time. Open the image and look. It needs Google Chrome, or Edge or Brave on macOS and Linux; CHROME_PATH points it at any other Chromium-based browser. An edit or a video URL needs no key.
shotstack inspect edit.json --at 0.5,4,8.05 # one sheet, written to inspect.jpg
shotstack inspect edit.json --bars map.json # a tile at every bar line from `analyze --output json`
shotstack inspect edit.json --at 3 --grid # one still with a grid labelled in output pixels
shotstack inspect <render-id> --at 1.2 --env stage # frames of a finished render
shotstack inspect https://…/clip.mp4 --at 0.5,1.8 # frames of a generated or uploaded video
A sheet holds six frames; more times write inspect-1.jpg, inspect-2.jpg and so on. Times past the edit's end are skipped and listed on stderr. The frames are Studio's canvas. If a render later differs from its sheet, tell the user and report it with shotstack feedback.
Five CLI rules
-
Pipe →
--output json. Default output is human-readable. When parsing programmatically or piping to another command, always pass--output json. -
Use
--watch, not a polling loop.shotstack render <file> --watchsubmits and polls in one shot;shotstack status <id> --watchpolls an existing render. Both exit when terminal:done(exit 0) orfailed(exit 1). Don't writewhile true; do ...; sleep 3; done. -
Compose from
shared/agent-core.md, thenshotstack validate. Its cheatsheet carries the property names, enums (transition/effect/position/fit) and rich-text fields you need — no schema download required.shotstack validate <file>then checks the JSON against the live schema offline and flags same-track overlaps, unloaded fonts and non-public URLs before you spend a credit. (For edge cases the full schema is at https://shotstack.io/docs/api/api.edit.json and the guide at https://shotstack.io/docs/guide/llms-full.txt.) -
Look at frames before a v1 render. Run
shotstack inspectwith a time at every cut, accent and word hit, and open the sheet: text too small, an element that never arrives, an empty scene or a caption wrapping to one word only show up in frames. Before timing anything to an event inside a generated clip, inspect the clip's URL to see when it happens. Ifinspectfinds no browser, tell the user the frames couldn't be checked here and hand off withshotstack studio <file>instead of rendering unchecked. -
Hand off to a human via
shotstack studio <file>when uncertain. Don't burn render credits iterating. Generate JSON →shotstack studio file.json(opens browser) → human reviews/tweaks → render only when right.
REQUIRED: Read shared/agent-core.md before composing any Edit JSON
Edit JSON does not follow CSS or web conventions, least of all the rich-text asset's styling fields (an html5 asset's css is ordinary CSS). Composing Edit JSON from training-data instinct will produce silently invalid renders. Read shared/agent-core.md first, every time. The most-failed conversions:
| You'd write (wrong) | API requires (right) |
|---|---|
alignment | align |
align.vertical: "center" | align.vertical: "middle" |
font.name | font.family |
duration | length |
transitions: [...] (array) | transition: { in, out } (object) |
fit: "cover" (CSS instinct) | fit: "crop" |
tracks[0] is the bottom (z-index instinct) | tracks[0] is the TOP layer |
The full ruleset (asset types, fonts, smart-string clip values, top-5 mistakes) lives in shared/agent-core.md.
Motion is yours to design. Built-in motion (transitions, effects, keyframes, rich-text animation) takes fixed options from the schema; html5 takes any seekable animation. references/motion.md covers what each layer can animate (transitions, effects, keyframes, rich-text animation, html5), the easing available and recipes; the Motion section of agent-core.md summarises it.
Exit codes
| Code | Meaning |
|---|---|
0 | Success |
1 | Permanent error — validation, missing key, 4xx, render failed |
2 | Transient error — 5xx, network, timeout. Safe to retry. |
References
Authoritative sources, in order of preference:
shotstack --helpandshotstack <command> --help— current CLI flag listingshared/agent-core.md— Edit JSON authoring conventions (shared with MCP server)- https://shotstack.io/docs/api/api.edit.json — OpenAPI Schema for the render API (machine-validatable)
- https://shotstack.io/docs/guide/llms-full.txt — full API docs in LLM-friendly single file
- https://github.com/shotstack/oas-api-definition/tree/main/schemas — raw OpenAPI YAML, source of truth for property names and enums
- https://shotstack.io/docs/guide/ — interactive HTML docs and guides
- https://shotstack.io/docs/api/ — interactive HTML API reference
- https://github.com/shotstack/shotstack-cli — this skill, and where
shotstack feedbackfiles issues
This skill ships sub-references for the gnarly bits:
references/onboarding.md— first-render discovery interview for new users: what to ask, and how answers map to a first Editreferences/ingest.md— uploading local files (and fetching URLs) so they can be used in an Edit: the upload→render workflow,--watch, status values, supported typesreferences/timeline.md— track layering, transitions, background music via audio assetsreferences/positioning.md— coordinate model,position/offset(fraction of frame, +y up), clip bounding box &fit, text sizing, transform orderreferences/caption.md— sizing per resolution, default style, the 5 named presets, alias pattern (asset type:rich-caption)references/svg.md— required attrs, supported elementsreferences/motion.md— what moves on each layer (transitions, effects, keyframes, rich-text animation,html5), the easing available, GSAP/CSS recipes, and the brand kit through merge fieldsreferences/html5.md— HTML5 asset: fields, preloaded libs (GSAP and its plugins, d3, anime, lottie), browser harness and seek rules, 3D, sizing, worked examplesreferences/html5-effects.md— the creative palette: every effect anhtml5clip can do, by common motion-design name (per-character text, stroke write-ons, mattes, blend modes, noise displacement, speed ramps, 2.5D camera, particles), with one-line recipes and what to avoid. Read before designing anhtml5clip.references/html5-snippets.md— copy-paste motion-graphic clips: kinetic headline, value reveal, shine sweep, pulsing CTA, film grainreferences/fonts.md— built-in fonts, Google Fonts URL pattern, custom-font workflowreferences/generation.md— per-model prompting craft for AI-generated video, images, speech and music, and what a timeline adds to a prompt. Read before writing anyprompt.references/beat-sync.md— cutting and animating to music: get the track first, analyse it, write every cue in bars, drivehtml5from the map, check frames at bar linesreferences/asset-library.md— placeholder videos, images, musicreferences/troubleshooting.md— common errors and fixes
If this skill and --help ever disagree, trust --help. If this skill and llms-full.txt ever disagree, trust llms-full.txt.