Command Line Interface

Bring OpenShot into your command-line workflow. Import footage, trim and arrange clips, apply effects, animate properties with keyframes, and export videos from your terminal. Use a few commands to automate repetitive edits, write a script for a recurring project, or let an AI agent help assemble and refine a video.

The command line works with the same projects as the editor. You can control an open editor and review changes as you go, or work in a headless session without opening a window. A session keeps your project open between commands, including its edits, undo history, and export jobs. Save it as an .osp project whenever you want to continue editing later.

Getting started

Use your installed OpenShot executable followed by --cli. Start with intro for a short guide to sessions, editing, animation, and saving, or help for the command overview. These commands do not need an active session. The examples below require an OpenShot build that includes command-line editing.

Linux AppImage

From the directory containing your downloaded AppImage:

./OpenShot.AppImage --cli intro
./OpenShot.AppImage --cli help

Replace OpenShot.AppImage with your downloaded filename. If AppImageLauncher shows desktop integration dialogs, set APPIMAGELAUNCHER_DISABLE=1 before launching the command:

APPIMAGELAUNCHER_DISABLE=1 ./OpenShot.AppImage --cli intro

For scripts or repeated commands, set it once in your current shell:

export APPIMAGELAUNCHER_DISABLE=1
./OpenShot.AppImage --cli session start

The variable must be set before launching the AppImage: AppImageLauncher can intercept it before OpenShot receives --cli. Relative media paths and @batch.json files are resolved from your working directory. Keep the AppImage file available while its sessions or exports are running.

Linux Snap

For the OpenShot Snap, use:

snap run openshot-qt --cli intro
snap run openshot-qt --cli help
snap run openshot-qt --cli session start

Snap’s file permissions apply to command-line editing too. Keep media, projects, and exports in locations the Snap can access, such as your home folder. To allow access to external drives, connect the removable-media permission:

sudo snap connect openshot-qt:removable-media

Windows

Important

Use openshot-qt-cmd.exe for command-line editing on Windows. This console executable displays command results, help, and errors in your terminal. The desktop executable, openshot-qt.exe, does not display standard output in an interactive terminal, leaving commands without visible feedback and making the CLI difficult to use.

In PowerShell, from the OpenShot installation directory:

& .\openshot-qt-cmd.exe --cli intro
& .\openshot-qt-cmd.exe --cli help
& .\openshot-qt-cmd.exe --cli session start

If you are in a different directory, use the full path to openshot-qt-cmd.exe. Keep --cli after the executable name.

macOS

For an installation in Applications:

"/Applications/OpenShot Video Editor.app/Contents/MacOS/openshot-qt" --cli intro
"/Applications/OpenShot Video Editor.app/Contents/MacOS/openshot-qt" --cli help

Finding commands

Throughout this guide, openshot-cli is shorthand for your installation’s command above, such as snap run openshot-qt --cli or ./OpenShot.AppImage --cli. Some installations also provide an openshot-cli command directly. When running from source, use python3 src/launch.py --cli in OpenShot’s Python environment.

Bare --cli, --cli help, and --cli --help show the same overview. Help becomes more specific as you navigate commands:

openshot-cli clip help
openshot-cli clip keyframe help
openshot-cli clip keyframe set help
openshot-cli edit help
openshot-cli text help
openshot-cli effects list
openshot-cli effects audiovisualization help
openshot-cli effects audiovisualization help --property background

Group help explains workflows with examples; operation help describes arguments and behavior. --help is equivalent to trailing help. All help commands work without an editing session.

effects list shows the available effects with short descriptions. Effect help explains their properties, defaults, choices, and ranges. effects instances lists effects already attached to clips, with parent clip IDs. Class names, display names, and underscore aliases identify the same effect.

Working with scripts and AI agents

AI coding agents such as Codex and Claude Code can use the CLI to inspect and edit OpenShot projects through terminal commands. Give your agent the path to your OpenShot executable, the media or project to work with, and the desired result: duration, dimensions, animation style, and output location. Ask it to read --cli intro before starting. The same commands work when you type them yourself or run them from a script.

Start with intro, then use command-specific help as needed. A useful workflow is to select a session, inspect the project, make a small set of changes, review the result, and save. Commands return structured JSON so scripts and agents can use object IDs and results directly instead of interpreting screen output.

  • Inspect before editing. Use returned IDs and property information instead of guessing names, track numbers, or timing. Select a session explicitly when more than one project is open.

  • Group repeated edits. Use edit apply for a sequence of changes or edit bulk to apply a template to selected clips. Validate with --dry-run before applying a batch.

  • Check animation. Choose a coordinate space, start with a few keyframes, and use easing presets for familiar motion. keyframe preview samples the curve so you can spot pauses or jumps before exporting. Review rendered motion as well; a contact sheet alone cannot show how an animation feels.

  • Save and follow exports. Save the project explicitly and check the export job’s status before treating an output as complete. If a request times out, inspect its status before repeating an edit.

The sections below explain these workflows and their timing conventions.

Sessions and outputs

Starting or finding a session

Start one headless session (without an editor window):

openshot-cli session start

To open an existing project at startup, add --project "/path/project.osp". The successful JSON response contains result.session_id. Copy that value. If OpenShot is already running, or you have forgotten the ID, find available sessions with:

openshot-cli session list

Choose the session for the project you intend to edit. You do not need to start a new session for each command.

Selecting a session

Tip

Set OPENSHOT_SESSION once, then run commands normally. Your terminal remembers the selected session, so you do not need to pass --session with every command. Use the PowerShell or Bash example below.

Replace SESSION_ID below with the session_id returned by session start or session list.

Windows PowerShell:

$env:OPENSHOT_SESSION = "SESSION_ID"
& .\openshot-qt-cmd.exe --cli timeline view
& .\openshot-qt-cmd.exe --cli export start "C:\path\test.mp4" --wait

Linux Bash:

export OPENSHOT_SESSION="SESSION_ID"
./OpenShot.AppImage --cli timeline view
./OpenShot.AppImage --cli export start "/path/test.mp4" --wait

On macOS, use the same export syntax. For macOS or Snap commands, substitute your installation’s executable from Getting started. The selection lasts for this terminal and commands launched from it. Set it again in a new terminal, or update it when switching to a different session.

The remaining editing and export examples assume OPENSHOT_SESSION is set. The next subsection shows how to capture the ID automatically for scripts.

To target a different session for just one command, use --session. It overrides OPENSHOT_SESSION without changing your terminal’s selection:

openshot-cli --session OTHER_SESSION_ID project get

With a packaged executable, put this override after --cli and before the command group: --cli --session OTHER_SESSION_ID project get.

Automatic selection only works when exactly one reachable session exists. If you see session_required, run session list and explicitly select the intended session. If it is no longer listed, start it again and use the new ID. Help, intro, and session discovery do not require a selected session.

Capturing the session ID automatically

Scripts can read result.session_id directly from the JSON returned by session start and set OPENSHOT_SESSION for subsequent commands. There is no need to copy the ID manually or read a log file. Check that startup succeeded before using the returned ID.

Windows PowerShell (set the executable path for your installation):

$openshot = "C:\Program Files\OpenShot Video Editor\openshot-qt-cmd.exe"
$reply = & $openshot --cli session start
if ($LASTEXITCODE -ne 0) { throw "OpenShot session startup failed" }
$session = $reply | ConvertFrom-Json
if (-not $session.ok -or -not $session.result.session_id) {
    throw "OpenShot did not return a session ID"
}
$env:OPENSHOT_SESSION = $session.result.session_id
& $openshot --cli timeline view

Linux Bash (requires jq to read JSON):

openshot="/full/path/to/OpenShot.AppImage"
export APPIMAGELAUNCHER_DISABLE=1
if reply=$("$openshot" --cli session start) &&
   session_id=$(printf '%s' "$reply" | jq -er 'select(.ok == true) | .result.session_id | strings | select(length > 0)'); then
    export OPENSHOT_SESSION="$session_id"
    "$openshot" --cli timeline view
else
    echo "OpenShot session startup failed" >&2
fi

The environment variable selects a session for commands launched from this terminal; it does not change a system-wide setting. Starting a session does not set the variable automatically. After stopping the session, clear the selection with Remove-Item Env:OPENSHOT_SESSION in PowerShell or unset OPENSHOT_SESSION in Bash.

Showing and stopping a session

To show the selected session in the editor:

openshot-cli session show

On a desktop, session show creates the editor in the same process and keeps the live project, IDs, history, export jobs, and connection. Repeated calls raise the existing window. session start --show opens it immediately. Sessions started without a display, or with QT_QPA_PLATFORM=offscreen/minimal, cannot later show a desktop window. For those sessions, save and open the project in a new desktop session. Once shown, close the session through the editor window.

Global options (--session, --timeout) go before the command. session serve stays in the foreground for supervisors; session start returns after a background host registers. session stop refuses unsaved changes and active exports. Use --discard only to intentionally discard unsaved edits.

Command output

Results are JSON on stdout, except the default text timeline view. Errors are JSON on stderr with exit status 1; argument-parser errors exit 2. Mutations return compact summaries with an inspect command. get returns native object JSON. Project replies include a revision; effect catalog replies do not require a session. Logs from headless sessions live beside their registry records. OPENSHOT_SESSION_DIR overrides the default ~/.openshot_qt/sessions directory.

Sessions accept commands locally on your computer. Keep the session registry private, since it contains the credentials used to access your editing sessions. Exports work from a snapshot, so you can continue editing while a job runs.

Opening and saving projects

An OpenShot project (.osp) stores your editable timeline. Exporting creates a finished video; saving the project lets you return to its clips, effects, and keyframes later. Save your project separately even when you also export a video.

Opening a project

Start a session with an existing project:

openshot-cli session start --project "/home/me/Videos/My Project.osp"

Add --show to open its editor window too. To use an editor that is already running, find it with session list. Set OPENSHOT_SESSION to its returned session ID, then open or inspect a project:

openshot-cli project open "/home/me/Videos/My Project.osp"
openshot-cli project get

Replace the example path with your own, and quote paths containing spaces. project open replaces the selected session’s current project. It refuses to discard unsaved edits unless you explicitly add --discard; save those edits first if you want to keep them. Opening through the CLI does not show interactive missing-media dialogs, so keep the project’s source media available.

For a new, empty project, use session start without --project, then import media and add clips as described under Editing.

Saving a project or a copy

Save to a new file, or create a separate version before making more changes:

openshot-cli project save "/home/me/Videos/My Project v2.osp"

To update an existing file, explicitly allow replacement:

openshot-cli project save "/home/me/Videos/My Project v2.osp" --overwrite

Always supply the destination path. Saving an .osp does not package all your source footage into that file; keep the referenced media available when moving or reopening the project.

Exporting a video

Automate rendering and exporting from scripts or AI agents, using the project’s settings or choosing a different output profile for each render. Export jobs can run in the background or wait for completion before your script continues. To render an MP4 using the project’s resolution and frame rate:

openshot-cli export start "/home/me/Videos/video.mp4" --wait

By default, OpenShot uses H.264 video and AAC audio. Replace the example path with your destination, using an existing folder and a new filename. Existing outputs are never overwritten. Exporting does not save your editable .osp project; use project save separately to keep your editing work.

The --wait option keeps the command running until the export completes or reports a failure. Review the finished video before sharing it.

Checking export progress

Leave off --wait to start an export in the background. The response includes a job ID you can use to check its progress:

openshot-cli export start "/home/me/Videos/video.mp4"
openshot-cli export status JOB_ID
openshot-cli export status JOB_ID --wait
openshot-cli export list

Replace JOB_ID with the returned ID. If waiting times out, the export keeps running; check the same job instead of starting another export. To stop a job, use export cancel JOB_ID. Each job captures the timeline when it starts, so later edits do not change an export already in progress.

Waiting defaults to 600 seconds; adjust this with --wait-timeout. This is separate from the global per-request --timeout. Export failures, cancellation, and wait timeouts exit with status 1 and include job details.

Exporting in multiple profiles

Export the same timeline at different resolutions or aspect ratios by choosing an export profile for each output. An export profile applies only to that job; it does not change the editing project’s profile. A profile sets dimensions, frame rate, and aspect ratio; an export preset selects encoding settings such as MP4/H.264.

Find the available profiles and inspect their settings:

openshot-cli profile list --search 720
openshot-cli profile list --search 1080
openshot-cli profile get builtin:01280x0720p0030_16-09

For example, export landscape versions at 720p and 1080p, then a square version at 1080 by 1080. These profiles all use 30 fps:

openshot-cli export start "/home/me/Videos/video-720p.mp4" --profile builtin:01280x0720p0030_16-09 --wait
openshot-cli export start "/home/me/Videos/video-1080p.mp4" --profile builtin:01920x1080p0030_16-09 --wait
openshot-cli export start "/home/me/Videos/video-square.mp4" --profile builtin:01080x1080p0030_01-01 --wait

Use a different output filename for each version. Keep edits unchanged between jobs when you want matching versions. Changing aspect ratio can change framing: review each output, especially titles and animated subjects. For a separately composed square or portrait version, save a project copy, change its project profile, and adjust the clips before exporting. See Profiles and the export settings below for custom profiles and encoding options.

Batch exporting multiple projects

Reuse one headless session to render several saved projects in sequence. Open a project, export it with --wait, then open the next project. The examples below use each project’s own resolution and frame rate and create MP4 files beside the .osp files. Add --profile PROFILE_ID to the export command to use one output profile for every project.

First run the matching automatic session-ID example above successfully, in the same terminal. It defines openshot and selects the new session. Replace the project paths below with your own. Use distinct output names that do not already exist; the examples check all destinations before starting the batch.

Windows PowerShell:

$projects = @(
    "C:\VideoProjects\First.osp",
    "C:\VideoProjects\Second.osp"
)
foreach ($project in $projects) {
    if (-not (Test-Path -LiteralPath $project -PathType Leaf)) {
        throw "Project not found: $project"
    }
    $output = [System.IO.Path]::ChangeExtension($project, ".mp4")
    if (Test-Path -LiteralPath $output) { throw "Output already exists: $output" }
}
foreach ($project in $projects) {
    $output = [System.IO.Path]::ChangeExtension($project, ".mp4")
    & $openshot --cli project open $project
    if ($LASTEXITCODE -ne 0) { throw "Could not open: $project" }
    & $openshot --cli export start $output --wait --wait-timeout 86400
    if ($LASTEXITCODE -ne 0) { throw "Export needs attention: $output" }
}
& $openshot --cli session stop
if ($LASTEXITCODE -ne 0) { throw "Could not stop the session" }
Remove-Item Env:OPENSHOT_SESSION

Linux Bash (the parentheses keep error handling local to the batch):

(
    set -e
    : "${OPENSHOT_SESSION:?Run the session startup example first}"
    projects=(
        "/home/me/VideoProjects/First.osp"
        "/home/me/VideoProjects/Second.osp"
    )
    for project in "${projects[@]}"; do
        test -f "$project" || { echo "Project not found: $project" >&2; exit 1; }
        output="${project%.osp}.mp4"
        test ! -e "$output" || { echo "Output already exists: $output" >&2; exit 1; }
    done
    for project in "${projects[@]}"; do
        "$openshot" --cli project open "$project"
        "$openshot" --cli export start "${project%.osp}.mp4" --wait --wait-timeout 86400
    done
    "$openshot" --cli session stop
) && unset OPENSHOT_SESSION

Both recipes stop the batch on a command failure and leave the session available for inspection. The wait limit here is 24 hours per export. A wait timeout leaves the render running: use export list and export status JOB_ID --wait before retrying. Completed videos remain on disk; remove completed projects from the batch before resuming. After resolving a failure, stop the session and clear its environment variable when you are finished.

Choosing presets and encoding settings

Discover the installed export presets and supported settings:

openshot-cli export preset list
openshot-cli export preset get builtin:format_mp4_x264
openshot-cli export capabilities
openshot-cli export start /tmp/reel.mp4 --preset builtin:format_mp4_x264 --quality med --wait

Export also accepts --from-file FILE_ID with optional --create-custom. Settings resolve in this order: project defaults, preset, advanced JSON, explicit profile/quality/range flags. Advanced JSON exposes video/audio codecs and bitrate, audio layout/rate/channels, native codec options, hardware device settings, and thread counts.

For example, select an encoder option through advanced JSON:

openshot-cli export start /tmp/small.mp4 --profile builtin:00640x0360p0030_16-09 --json '{"video_options":{"preset":"fast"}}' --wait

Validating export settings

Check settings before starting a render:

openshot-cli export validate /tmp/reel.mp4 --preset builtin:format_mp4_x264

Capabilities report compiled codec availability, not physical GPU availability. Validation goes further: it opens the encoders (including hardware encoders) and the container with the exact settings, in a separate process, without writing a file. A combination the container can’t hold fails with incompatible_export, FFmpeg’s own explanation, and the setting to change (details.cause.path):

openshot-cli export validate /tmp/song.mp3 --json '{"mode":"audio","format":"mp3","audio_codec":"aac"}'

The export worker runs the same check before rendering.

Rendering a frame range

Use --start-frame and --end-frame to render part of the timeline. Ranges are inclusive and one-based at the export profile’s FPS. For example, render the first 90 frames at 30 fps (three seconds):

openshot-cli export start /tmp/excerpt.mp4 --profile builtin:01280x0720p0030_16-09 --start-frame 1 --end-frame 90 --wait

Audio-only exports and image sequences

Choose an output mode with advanced JSON:

openshot-cli export start /tmp/music.wav --json '{"mode":"audio","format":"wav","audio_codec":"pcm_s16le"}' --wait
openshot-cli export start /tmp/frames --json '{"mode":"image_sequence","format":"png"}' --end-frame 3 --wait

Image sequences require a new output directory. Existing outputs are never overwritten.

Editing

Adding clips and effects

Use the IDs returned by import/add/list, and discover layer numbers with project get:

openshot-cli file import /absolute/path/video.mp4
openshot-cli clip add FILE_ID --layer 2000000 --position 3 --start 10 --end 17 --volume 0
openshot-cli clip set CLIP_ID --json '{"volume":0.5}'
openshot-cli clip keyframe set CLIP_ID --property volume --frame 301 --value 0
openshot-cli clip keyframe set CLIP_ID --property volume --frame 331 --value 1
openshot-cli effects add CLIP_ID saturation
openshot-cli effects set EFFECT_ID --json '{"saturation":1.2}'
openshot-cli project save /absolute/path/edit.osp

Choose the project profile early when possible; populated projects also support profile changes through the existing FPS conversion and undo system. --audio-only on clip creation suppresses video, including embedded cover art in music files. To use that clip for Audio Visualization instead, enable its video and audio, and follow the effect’s help for transparent overlays and layer placement.

Understanding clip timing

The example keyframes assume a 30fps project and a clip trimmed at source 10s. Position is in timeline seconds; start/end are source seconds, with end exclusive. Frames start at 1. File thumbnail frames use source FPS. Timeline frames use project FPS. Clip keyframes use source coordinates at project FPS, so trimming the clip does not move its first visible keyframe to frame 1.

Changing properties

set merges top-level properties. Scalars turn keyframed properties into constants. A supplied nested curve replaces that curve; use keyframe set to change just one point. JSON arguments accept inline JSON, @file.json, or - for stdin. Property names, types, enums, keyframes, references, and timing are validated before editing the project. Errors identify the field, expected value, received value, and a correction where possible. GUI slider ranges are advisory where the engine supports values beyond them.

Adding fades

clip fade ID --in 0.5 --out 0.5 calculates source-trim keyframe coordinates automatically. It replaces the alpha curve; --property volume --value 0.25 instead creates an audio fade with a 0.25 peak gain. Durations must fit between the first and last visible frames; fade-out reaches zero on the last frame.

Splitting clips

clip split ID --at 6.5 uses timeline seconds, snaps to the nearest project frame, and keeps both halves. It retains source-coordinate curves and duplicates effects with fresh IDs on the right half, following the editor’s slicing behavior. The left half retains its ID. The response reports requested/actual split times and both summaries; a named batch result supports {"$ref":"cut.right.id"}. Splits reject endpoints and locked tracks. Undo restores the original clip in one transaction.

Clip menu presets

The editor’s clip menu presets use the same code from the command line. Each command lists its presets in its help, and each one is a single undo step:

openshot-cli clip motion CLIP_ID --preset slide-in-left
openshot-cli clip motion CLIP_ID --preset pulse --at 4.5
openshot-cli clip look CLIP_ID --effect ColorGrade --preset warm_up
openshot-cli clip look CLIP_ID --effect all --preset none
openshot-cli clip speed CLIP_ID --mode forward --factor 2
openshot-cli clip speed CLIP_ID --mode freeze --at 3 --duration 2
openshot-cli clip repeat CLIP_ID --passes 3 --pattern pingpong
openshot-cli clip waveform CLIP_ID

Motion presets are relative to the clip’s current transform. Look presets add or replace one effect, and none removes it. Speed and repeat retime every keyframe and change the clip’s length; clip speed --mode reset restores normal speed. Other menu actions are plain edits: rotate and layout with clip set, crop with effects add Crop. The commands also work in edit apply and edit bulk.

Adding and styling text

text add creates a text and places it as a clip, using the same text as the editor’s Text tool. Options you leave out use the editor’s default style:

openshot-cli text add --text "Opening Night" --layer 5000000 --position 2 --duration 4 \
    --place lower-third --font "Noto Sans" --size 72 --bold --color "#ffffff" \
    --background "#80000000" --background-padding 16 --background-corner 12
openshot-cli text get CLIP_ID
openshot-cli text set CLIP_ID --stroke black --stroke-width 3
openshot-cli text set CLIP_ID --text $'Two\nlines' --line-spacing 1.4
openshot-cli text fonts --search noto
openshot-cli text list --search opening

The words, font, size, alignment, box width and default colors belong to the text in Project Files and are shared by every clip that uses it, just like in the editor. text set on one clip changes all of them and lists them in changed_clip_ids; --this-clip-only gives that clip its own copy first. clip add FILE_ID places another clip of a text from text list. Sizes are in pixels at the project resolution, and colors are #RRGGBB, #AARRGGBB (with alpha), a CSS name, or transparent. --place puts the box at the center, an edge or corner, or a lower third. --line-spacing is a multiple of the normal distance between lines (1 is normal), and --background-corner rounds the background and border corners by that many pixels.

A text clip is an ordinary clip. Position, scale, rotation, opacity, timing, fades, motion presets and effects all use the normal clip commands. Font size, padding, box width, and letter and line spacing set the size of the text box, so they cannot be keyframed; to animate the size of text, keyframe the clip’s scale. Each clip can animate its own text colors and outline and border widths with the same keyframe commands as any other property:

openshot-cli clip keyframe list CLIP_ID
openshot-cli clip keyframe set CLIP_ID --property text_color.alpha --space clip --unit seconds --at 0 --value 0
openshot-cli clip keyframe set CLIP_ID --property text_color.alpha --space clip --unit seconds --at 1 --value 255

The animated properties are text_color, text_background, text_stroke and text_border (colors, with .red, .green, .blue and .alpha from 0 to 255), plus text_stroke_width, text_border_width and text_background_corner. A clip’s own animation wins over the shared style, and text get lists which styles a clip animates. text reset CLIP_ID returns a clip to the default style, like Text → Reset Style; --keyframes-only just removes the clip’s own animation. To style many texts at once, select them with {"text":true}:

openshot-cli edit bulk --select '{"text":true}' --json '[{"method":"text.set","params":{"font_family":"Noto Sans","stroke_width":2}}]'

Applying a batch of edits

edit apply --json @edits.json --expect-revision 12 accepts up to 256 ordered mutation commands, using dotted command names such as clip.set and effects.add (the older effect.add spelling also works):

[
  {"method":"project.profile.set","params":{"id":"builtin:01280x0720p0024_16-09"}},
  {"method":"file.import","as":"media","params":{"path":"/tmp/video.mp4"}},
  {"method":"clip.add","as":"shot","params":{"file_id":{"$ref":"media.id"},"layer":1000000,"start":10,"end":15}},
  {"method":"clip.fade","params":{"id":{"$ref":"shot.id"},"fade_in":0.5,"fade_out":0.5}}
]

The optional as binds a result for later commands in the same batch. A {"$ref":"shot.id"} object substitutes that result’s field. References only resolve earlier names; misspellings, forward references, and duplicate names fail before live updates. The response includes ordered compact results and a refs map of actual IDs. All changes in a successful batch form one undo/redo step. project.profile.set also supports populated timelines. Opening, saving, exporting, and inspection commands stay outside edit batches. Each command’s help lists its JSON parameter names, including the underscore spelling of shell flags (for example, --fps-num becomes fps_num).

Validating batches and handling errors

All commands in edit batches preflight against a detached project before any live updates. Invalid input leaves the live project and revision unchanged. Valid batches form one undo group. Unexpected runtime failures can still produce partial changes; errors report completed operations. A timeout does not imply cancellation, so inspect state before retrying mutations.

Precise keyframe editing

clip, transition, and effects support keyframe list, set, remove, clear, transform, copy, and paste. Property paths can address nested curves, such as color.red on a Chroma Key effect. Editing a nested curve preserves sibling channels. Run keyframe list ID without a property to discover curve paths and point counts. Discovery and point listings include trim/position timing context; point listings also report native frame coordinates. get and properties expose the complete native object and property metadata. Errors identify invalid fields, suggest close property names, and explain coordinate corrections.

Choose coordinates explicitly with --space native|clip|timeline and --unit frames|seconds. All frames use project FPS and are 1-based; seconds start at zero and snap to the nearest frame. Native is the existing engine keyframe coordinate (including source trim). Clip coordinates start at the visible clip in-point; timeline coordinates start at project time zero. Attached effects use their parent clip’s timing. These coordinates address animation time, not the media frames selected by a time-remapping curve.

For a clip positioned at 5 seconds, trimmed at 2 seconds, in a 30 fps project, clip frame 1, timeline frame 151, and native frame 61 address the same point. Position and trim snap independently to the project frame grid. Listing an entire curve can include hidden points with nonpositive clip/timeline coordinates. Legacy --frame still means a native frame and cannot combine with --at.

Examples:

openshot-cli clip keyframe set CLIP --property location_x --space clip --unit seconds --at 0 --value -1
openshot-cli clip keyframe set CLIP --property location_x --space clip --unit seconds --at 1 --value 0 --interpolation bezier --handles '{"handle_left":{"X":0.2,"Y":0.9}}'
openshot-cli effects keyframe set EFFECT --property color.red --space clip --at 31 --value 200
openshot-cli clip keyframe list CLIP --property location_x --space clip --unit seconds
openshot-cli clip keyframe transform CLIP --property location_x --space clip --start 1 --end 31 --scale 2 --offset 15
openshot-cli clip keyframe copy TARGET --property location_x --source-id SOURCE --space clip --start 1 --end 31 --at 1 --mode merge
openshot-cli clip keyframe remove CLIP --property location_x --space clip --at 31
openshot-cli clip keyframe clear CLIP --property location_x --value 0

Interpolation, easing, and preview

Interpolation describes the segment into the destination point. Linear gives a steady rate between points. Constant holds the preceding value until the destination, then jumps. Native default Bezier handles ease at both ends of each segment. Adding an intermediate point can therefore introduce an unintended slowdown; for one eased move, start with two endpoints. Normally leave handles alone and choose a named preset for a specific style.

Discover the same easing presets used by the editor’s menus, without a session:

openshot-cli clip keyframe presets

Apply a preset to the incoming segment by setting its destination:

openshot-cli clip keyframe set CLIP --property scale_x --space clip --unit seconds --at 0 --value 1
openshot-cli clip keyframe set CLIP --property scale_x --space clip --unit seconds --at 4 --value 1.2 --easing ease-in-out

The easing option implies Bezier. It sets the previous point’s outgoing handle and the destination’s incoming handle together, preserving other handles and point values. An earlier point must exist. Do not combine it with custom handles or a different interpolation. Presets work in batches and bulk templates. The GUI preset ease (“Ease (Default)”) differs from the native handles used by plain Bezier interpolation. Back presets can overshoot endpoint values.

Inspect motion before rendering, using the native curve evaluator:

openshot-cli clip keyframe preview CLIP --property scale_x --space clip --unit seconds --start 0 --end 4
openshot-cli clip keyframe preview CLIP --property scale_x --space clip --unit seconds --at 2

Preview is read-only and works identically for effects and transitions. It returns values and signed incoming_rate / outgoing_rate in property units per second, calculated from immediately adjacent frames. These are finite differences, not analytic derivatives. At native frame 1 the incoming rate is null. Adjacent-frame rates can inspect outside the requested range. Near-zero rates around an interior point reveal a pause; differing rates reveal a speed change. Constant interpolation reveals a jump at the destination.

Without a range, preview spans the curve’s first and last points. Ranges are inclusive, with 17 evenly spaced samples by default (–count: 2–256). Keyframes and their immediate neighbors inside the range are also included, so a sparse sample count will not hide a keyframe stall. The maximum is 1024 samples; larger requests require a narrower range. –at samples one frame. Preview reports requested-space coordinates and actual native frames; seconds snap to project frames as they do for editing.

For advanced custom handles, both X and Y are normalized to the segment: X is a fraction of its frame span; Y is a fraction of its value change. The first control comes from the previous point’s handle_right, the second from the destination’s handle_left. Native defaults are right=(0.5, 0), left=(0.5, 1), with flat endpoint tangents. Changing handle_type alone does not recalculate a continuous tangent through surrounding points. Existing handles are preserved when moving a point.

Keyframe ranges are inclusive, unlike clip-selection time ranges. List emits points whose co.X values use the requested coordinate space/unit. Pass that array to keyframe paste --json @points.json with the same space/unit, choosing --mode merge (replace matching frames, retain others) or --mode replace (replace the entire curve). copy accepts a source of the same object kind, an optional --source-property, and anchors the first selected source point at --at on the target. Other curves and source objects remain unchanged.

transform applies a positive time scale around the first selected point, or --pivot, followed by a signed --offset in the chosen unit. Frame snapping that creates duplicate coordinates is rejected, including collisions with points outside the selected range. Native coordinates must remain at least 1. Native normalized Bézier handles and interpolation travel with each point; handles are not absolute frame coordinates. set --handles changes only supplied handles. Interpolation belongs to the destination point.

clear retains a constant base point at native frame 1: specify --value or sample the existing curve with --at (default native frame 1). Removing the last point also retains a constant base, so subsequent keyframe additions remain valid.

Selecting and editing many clips

Use edit apply --dry-run to validate a batch without changing the project. Use edit bulk to repeat a small command template for each selected clip, with all changes grouped into one undo step.

First preview a selection:

openshot-cli edit select --json '{"layer":1000000,"start":5,"end":20,"effect":"Saturation"}'

Selectors support ids (unique clip ID array), layer, start/end (timeline seconds), file_id, effect (class name or alias), and text (true selects text clips). Filters combine with AND. Time ranges select clips overlapping [start, end); they do not trim those clips. Results are ordered by position, layer, then ID, and include IDs, summaries, lock state, and the current revision. Unknown IDs are errors. An empty selector is rejected; use {"all":true} explicitly for every clip. Selections are bounded to 256 clips and are never silently truncated.

For example, save this array as templates.json:

[
  {"method":"clip.adjust","params":{"values":{"position":{"add":2},"volume":{"multiply":0.5}}}},
  {"method":"effects.add","as":"look","params":{"type":"Saturation"}},
  {"method":"effects.keyframe.set","params":{"id":{"$ref":"look.id"},"property":"saturation","space":"clip","at":1,"value":0}},
  {"method":"effects.keyframe.set","params":{"id":{"$ref":"look.id"},"property":"saturation","space":"clip","at":31,"value":1.2}}
]

Validate it, then apply against the revision returned by selection:

openshot-cli edit bulk --select '{"ids":["CLIP_A","CLIP_B"]}' --json @templates.json --dry-run
openshot-cli edit bulk --select '{"ids":["CLIP_A","CLIP_B"]}' --json @templates.json --expect-revision 42

Existing-clip commands inherit id; effects.add inherits clip_id. Omit these target parameters in templates. Effect edits must reference an earlier named result. Names are local to each selected clip, so look.id refers to a different effect for each clip. To change existing effect instances by explicit ID, continue using edit apply. The selected ID set is fixed before expansion; changes to position or effects do not change the remaining targets.

clip set applies absolute properties; clip adjust applies multiply then add to a numeric property or every value in a curve, preserving point timing, interpolation, and normalized handles. It validates resulting values, including nonnegative positions and volume. Structural fields remain protected.

Bulk operations reject empty selections, locked target tracks, and more than 256 expanded commands. Every expanded operation passes detached preflight before any live edit. Dry runs do not reserve generated IDs. Use --expect-revision to reject stale selections. Successful batches are one undo step, including after save/reopen. GUI refreshes are batched. Unexpected runtime/listener errors can still leave a partial transaction; the error reports completed operations and undo reverts that group, as with edit apply.

Profiles

Discover profiles and match imported video without guessing IDs:

openshot-cli profile list --search 720
openshot-cli profile get builtin:01280x0720p0024_16-09
openshot-cli profile match --file FILE_ID
openshot-cli project profile get
openshot-cli project profile set --from-file FILE_ID
openshot-cli project profile set builtin:01280x0720p0024_16-09
openshot-cli project profile set --json '{"width":640,"height":352,"display_ratio":{"num":20,"den":11},"fps":{"num":24000,"den":1001}}'

Catalog entries include stable IDs, descriptions, dimensions, rational FPS, aspect ratios, and scan settings. List/search is paginated. Source matching returns exact IDs and ranked alternatives with explicit differences. Setting from a file requires an exact match unless --create-custom is specified; it never silently chooses a nearby profile. Still images and audio-only sources cannot define a video profile. Matching uses declared source FPS.

Custom settings are embedded in the saved project, including rational rates, so reopening does not require installing a separate profile file. Project profile changes use existing frame-rate conversion and one undo transaction. Undo/redo restores clip timing and keyframes, including rounding-sensitive positions. Export can independently select a profile without changing the project.

Saved undo history follows the editor’s history-limit preference. The limit is a soft action budget: all records belonging to retained transactions are kept, so saving cannot truncate a large batch into a partial undo action. Zero disables saved history. The separate 256-command batch request bound still applies.

Inspecting media and timelines

Inspect clip timing and track layout as text or JSON, or render images to review composition and framing before exporting.

Timeline summaries

Use a text view for a quick overview, or structured JSON for scripts and agents:

openshot-cli timeline view --start 5 --end 12
openshot-cli timeline view --start 5 --end 12 --format json
openshot-cli timeline overview --start 5 --end 12

timeline view defaults to compact text with used tracks, object IDs, timeline/source intervals, stream state, gain, and gaps/overlaps. Use --detail summary|clips|full to choose detail, --format json for structured context, and --start/--end, --layer, and pagination to focus the result.

timeline overview supplies compact structured context without image bytes: ordered IDs, sequence per track, timeline/source intervals, visible trim ranges, frame coordinates, audio/video state, effects, and neighboring gaps or overlaps. Intervals and frame spans are end-exclusive; frame numbers are one-based. Source frames use source FPS; timeline and keyframe coordinates use project FPS. Use --layer and --start/--end to focus, and --limit/--offset to paginate (default 100, maximum 500 items). Time-remapped clips explicitly withhold inferred source mappings. Use the returned revision with edit apply --expect-revision.

Frame previews and contact sheets

Render a single frame with thumbnail or sample a range with strip. Use file to inspect source media and timeline to inspect the composed video, including effects and layered clips:

openshot-cli file thumbnail FILE_ID --frame 301 --output /tmp/source.png
openshot-cli file strip FILE_ID --start 10 --end 20 --count 12 --output /tmp/source-strip.png
openshot-cli timeline thumbnail --frame 91 --output /tmp/timeline-frame.png
openshot-cli timeline strip --start 0 --end 20 --count 12 --output /tmp/timeline-strip.png

Frame images default to 320x180 pixels; contact sheets default to 160x90 per tile, plus timecode labels. Use --width and --height to choose output pixels. Responses include exact sample/frame metadata. Contact sheets help review composition across a sequence; use keyframe previews and rendered video to assess motion between those samples.

Timeline images

Capture the editor’s track layout, including its ruler, thumbnails, effects, transitions, and waveforms:

openshot-cli timeline view --start 0 --end 20 --pixels-per-second 80 --output /tmp/tracks.png

Specifying --output selects image format; --format image also selects it explicitly. The capture does not change the editor’s viewport or project. Responses include clip IDs and timing alongside pixel bounds.

Images default to 1280 pixels wide, with height fitted to used tracks. Use --width, --height, or --all-tracks to adjust the layout, and --track-size or --track-label-width to adjust tracks and labels. The start/end range determines zoom; --pixels-per-second instead derives the width from the time range.

Audio waveform views

Choose --mode waveforms to inspect audio envelopes on the timeline:

openshot-cli timeline view --start 5 --end 12 --mode waveforms --output /tmp/waves.png

--mode auto uses the existing cached waveform display; --mode thumbnails shows thumbnails instead. Waveforms represent source peak/RMS levels with clip volume and timing adjustments, before audio effects or mixing.

Uncached waveform extraction decodes whole sources, limited to 600 seconds per source and 1200 source-seconds per request. Narrowing the visible range does not reduce that decoding work. For longer sources, generate waveforms in the editor first or use thumbnail mode. Subsequent requests can reuse cached waveforms.

Image output and limits

Image paths must be new PNG files in existing directories. Images are limited to 4096 pixels per axis, 8,388,608 total pixels, and 64 contact-sheet samples. Requests beyond these limits fail before rendering.

Images are written to files; JSON responses include their paths and image_bytes sizes. Inspection waits for the image to finish, and large requests can briefly occupy the editor.

Handling command timeouts

A request timeout does not mean a mutation failed. Use the operation ID in the error with operation get ID before retrying. operation list discovers recent mutations and their states, revisions, and outcomes. Completed operations retain their results when small enough, including returned object IDs. Storage is bounded to 100 operations and 4 MiB, with individual result bodies omitted above 256 KiB. These records last only for the running session. They do not restore projects after a crash or prevent a repeated command from applying the same edit again. Export jobs have their own status/list commands.