POST /v1/render/videos records a demo of a web app from a script. The script is a list of beats: each beat says one line of narration and performs browser steps while the line is said. The result is a job.

Record a video

bash
curl -s "https://beta-api.b3os.org/v1/render/videos?wait=30" \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "source": {"url": "https://app.example.com", "profile": "acme-staging"}, "beats": [ {"say": "Open the billing page.", "do": [{"kind": "click", "target": {"role": "link", "name": "Billing"}}]}, {"say": "Switch to annual and watch the price update.", "do": [{"kind": "click", "target": {"text": "Annual", "exact": true}}]} ], "voice": {"model": "kokoro-82m", "voice": "af_heart"}, "captions": {"burn_in": "karaoke", "sidecars": ["vtt"]}, "style": {"background": "midnight", "frame": "browser-dark", "cursor": "mac"}, "formats": ["mp4", "gif", "poster"] }'

The voice model and voice come from GET /v1/infer/models and GET /v1/infer/audio/voices; the values above are examples. Narration is optional: a beat without say is silent, and hold_ms keeps the camera on a beat after its steps end.

The script

FieldMeaning
source.urlWhere the recording starts
source.profileA vision profile to start signed in
beatsUp to 100 beats, each with say (up to 2,000 characters), do (up to 50 steps), an optional title and hold_ms
voiceSpeech model, voice and speed (0.5 to 2)
captionsburn_in (none, static, or karaoke, which also highlights the spoken word), sidecars (vtt, srt), and line limits: 42 characters, 2 lines and 20 characters per second by default
styleBackground, frame, cursor, caption and click-effect presets, plus overrides
cameraauto_zoom (on by default) zooms toward the element each step acts on, up to max_zoom (2 by default, 3 at most)
viewportThe browser's size in CSS pixels
outputwidth, height and fps (24, 25, 30, 50 or 60) of the video
formatsAny of mp4, gif and poster; mp4 and poster by default
seed, start_timeSeed the page's randomness and fix its clock, so a re-render is identical

Steps use the browser action kinds navigate, click, hover, type, key, scroll, select and wait, with the same fields as in browser sessions. A script that fails validation is refused with script_invalid before anything records; a step that fails while recording ends the job with script_step_failed, and step names it, such as beats/1/do/0.

Follow the job

A video is a job. Its events stream at GET /v1/render/videos/{video_id}/events: the lifecycle events, video.phase as it moves through voice, plan, capture, compose, encode and upload, and video.artifact as each file becomes available, poster first. You can also wait on the create call with ?wait=, or pass a webhook.

When it succeeds, result holds the duration, size and frame rate, and artifacts lists the files with signed URLs. MP4 files are H.264 with BT.709 color. POST /v1/render/videos/{video_id}/cancel stops the job; artifacts already made are kept and seconds already encoded are billed.

GET /v1/render/videos/{video_id}/timeline returns the compiled timeline once planning is done: the narration with word timings, the timed actions the recorder replayed, the cursor path, camera keyframes, captions and style. Add frames=1 for the per-frame compositor state when you need to debug a frame.

Restyle a video

Restyling re-composes the archived raw capture with a new style, captions, output size or formats. No browser runs and the narration is reused; camera moves do not change.

bash
curl -s "https://beta-api.b3os.org/v1/render/videos/$VIDEO_ID/restyle?wait=30" \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"style": {"background": "sunrise", "frame": "browser-light"}, "captions": {"burn_in": "static"}}'

The result is a new video whose restyled_from names the source. The raw capture lives as long as the source video, 7 days; after that, or for a video that did not succeed, restyle fails with restyle_unavailable.

Delete

DELETE /v1/render/videos/{video_id} cancels the job if it is still running, then deletes the video, its artifacts and its raw capture.

Ask a question... ⌘I