- The CLI opens a Chrome window for you and writes the demo into your project. A script or an agent can drive it too.
- The Chrome extension records in your own browser, signed in as you, with no terminal.
Record with the CLI
Two commands bracket a session:start returns immediately, so your terminal stays free while you record. Every capture subcommand prints JSON, so a script can drive the same flow a person does. So can an agent: give it the agent skill and ask it to “record a demo of https://your.app”.
How it works
start launches Chrome with a debugging port and talks to it over the Chrome DevTools Protocol. It opens your URL in a new tab, injects a small recorder script, then spawns a detached listener process and hands your prompt back. The listener turns each click into a step until you run stop or cancel.
The window is visible by default, because you drive the product. --headless is only useful when something else drives the page: a script sending clicks over CDP, or --connect-to-browser <url> pointing at a browser you already control.
Chrome is found for you: Google Chrome first, then Chrome for Testing, Canary, or Chromium. Sites with bot protection tend to block the testing builds. --browser /path/to/chrome or the CHROME_PATH environment variable overrides the choice.
The tab is sized to 1440×900 by default and captured at 2× pixel density, so a default session writes 2880×1800 screenshots. start waits up to --timeout milliseconds (120000 by default) for the first page load, and refuses to record if Chrome lands on its own error page.
What a click becomes
Clicks produce steps. Scrolling and typing are recorded as motion and only show up as video. The initial page load is not a step. Each click produces one content step:- The background is the page as it looked at click time, before the click’s own repaint and before any navigation it triggers. The screenshot, the pointer, and the label all describe the same page.
- An annotation is placed at the point you clicked: a
messagewith thecursorvariant, readingClick on "Save changes". The label is the clicked element’s accessible name (aria-label,title,alt, its own text, or avalue,placeholder, orname), first line only, capped at 48 characters. When nothing usable is found, the text isContinue. - A zoom of 1.35× toward the click, eased back as the point approaches an edge.
--no-zoomleaves the screen unzoomed. advance.trigger: "click", so the viewer moves on by clicking the annotation.
- A click on a link is held. The recorder cancels the navigation, lets the source page be captured, then navigates for you.
- A click that opens a new tab is followed. For three seconds after a click, a page Chrome opens is treated as the one to keep recording.
What stop writes
stop builds the demo from the recorded screens and writes a folder:
--name, or the page host with www. trimmed, lowercased and hyphenated. If that folder exists it becomes onboarding-2, onboarding-3, and so on.
Without --out, stop must run inside a project. It writes into that project’s demos/ and appends the slug to interactive-demo.json when that file keeps a demos list. --out <dir> writes <dir>/<slug> instead and touches no project file.
The config gets a fresh demo id, --name as the title, and steps s1, s2, and so on. --compress-images re-encodes screenshots to WebP and keeps the PNG whenever the WebP is not smaller.
stop then tears the session down: the listener, Chrome, its temporary profile, and the working files. It prints the demo folder, the step count, and one label per step, so you can read the captured story without opening the JSON.
Video steps
Video needsffmpeg on PATH. start checks once, up front. With no ffmpeg it prints a warning to stderr, reports videoDisabledReason in its JSON, and records everything as stills for the whole session. --no-video asks for stills and silences the warning.
While a session runs, the listener keeps a rolling buffer of screencast frames. When you scroll or type and then click, that click commits the preceding motion as a video step instead of a still. Only the densest continuous run of frames is kept, so idle frames before the motion and the settle after the click are dropped.
The clip opens with a half-second hold on its first frame and is padded to at least 1.5 seconds by holding its last frame. It is encoded as VP9 WebM, with its first frame written alongside as the poster. A burst under 10 frames or 1.2 seconds, or one whose frames are all identical, falls back to a still.
A video step carries the same cursor annotation and click-to-advance as a screenshot step. The auto-zoom applies to screenshot steps only.
Check and undo while you record
capture status reads the session and reports without touching the browser:
ready: the recorder armed.browserAlive: the capture browser is still running. If this isfalse, further clicks record nothing. Runstopto keep what you have.stepCount,stepLabels,steps: the story so far, one entry per recorded click.
capture undo drops the most recent step. Use it for a probing click you do not want in the demo.
capture cancel throws the session away. It kills the listener and Chrome, removes the working files, and writes no demo.
You rarely need a session id. With one session running, every subcommand finds it. With more than one, they stop and list the ids so you can pass --session <id>.
Capture an app behind a login
Two things make a login survive.--profile <name> points Chrome at a persistent user-data directory instead of a throwaway one, so cookies live on between captures. A bare name maps to a folder under the capture home. A value containing a slash is treated as a directory path. capture profiles lists what you have, and whether each profile holds cookies.
Signing in inside the capture browser does not always work. Identity providers reject an automation-controlled browser, even when a person is doing the clicking. capture login opens a separate, ordinary Chrome window on the same profile, with no debugging port and no automation flags:
start evicts the login window from the profile before taking it over, so its cookies are flushed first. A persistent or attached profile is never deleted on stop, cancel, or an interrupted start.
When a capture goes wrong
Nothing was recorded
Nothing was recorded
stop with zero steps prints ok: false with the reason and cleans the session up, so no cancel is needed. The initial page load is not a step. A step needs an actual click.The recorder never armed
The recorder never armed
start waits up to 15 seconds for the listener to report ready. If it does not, start fails and prints the tail of the listener log and the Chrome log. Nothing is left behind. Start again.The page was still loading when you clicked
The page was still loading when you clicked
The step shows what was on screen at click time, half-loaded skeletons included. Undo it, wait, and click again.
start was interrupted
start was interrupted
Ctrl+C during
start tears down the Chrome and listener it had already spawned and removes the half-written session.Chrome crashed mid-session
Chrome crashed mid-session
Each step is written to the session file as it is recorded, so the steps before the crash are still there. Run
capture stop and it exports them.The session file is unreadable
The session file is unreadable
Any command that touches it says so and names the session.
capture cancel --session <id> cleans up what it can and reports what it recovered.Where session files live
A running capture keeps its state outside your project, under~/.interactive-demo/capture/:
sessions/<id>.jsonis the live session: the browser it launched, the tab it is recording, and every screen recorded so far.captures/<id>/holds the screenshots and video frames recorded so far, pluslistener.log.profiles/<name>/holds persistent Chrome profiles.
INTERACTIVE_DEMO_CAPTURE_HOME moves all of it somewhere else.
Every capture flag and its default is in the CLI reference.
The Chrome extension
Interactive Demo Capture records a demo in your own Chrome, signed in as you, with no terminal. Install it from the Chrome Web Store.It is a separate extension from the hosted Inkly demo agent’s, which is covered in Chrome extension. Each works only with its own product.
1
Open your product
Open your product in a tab and go to where the demo should begin.
2
Start recording
Open the extension and pick Start Recording. Every click becomes a step: the page as it was just before the click, with a cursor on what you clicked. Scrolling or typing before a click is kept as a short video step. The popup counts the steps as you go.
3
Stop and save
Pick Stop & save. The recording stays in the extension until you decide what to do with it.
- Download ZIP
- Upload to Inkly
The zip holds one demo folder, The demo lands in
demo.config.json and its assets/, named after the site you recorded. Import it into a project with no unzip step:demos/acme-3f91b2/. Add --demo <slug> to choose the folder name.This path works fully offline. Nothing leaves your machine. The popup also copies the command, or a prompt that hands the import and a caption review to your agent.After the capture
A captured demo is an ordinary demo folder, the same thinginit writes and the editor edits. From here:
interactive-demo validatechecks the config and that every referenced file exists.interactive-demo devpreviews it. Rewrite the generatedClick on "…"text into something worth reading, in the editor or in the config.interactive-demo publishputs it online, orinteractive-demo buildwrites the static folder to deploy. See Publish and self-host.

