AI Recorder
Describe a flow in plain words and an agent drives a real browser to produce a screen recording of it. No screen capture, no narration script, no editing.
The AI Recorder is included on every paid plan. On a free plan, starting a recording returns
403.
Start a recording
POST /v1/recordings
curl -X POST https://api.vidocu.ai/v1/recordings \
-H "Authorization: Bearer vdo_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Show how to invite a teammate and set their role to Editor",
"url": "https://app.example.com/settings/team",
"device": "desktop"
}'
{ "jobId": "video_recording_1786093699160_motd1r", "status": "pending" }
Returns 202. Recordings take minutes, not seconds - poll the job.
Two recordings run per workspace at a time; a third start returns 429. Recording browsers are a
shared pool, so a job may also sit queued briefly before it starts - progress.step reports
queued while it waits.
| Field | Type | Description |
|---|---|---|
prompt | string | What the recording should show. Required |
url | string | Where to start |
device | desktop | mobile | Viewport to record in |
pacing | relaxed | standard | brisk | Replay speed of the finished video |
mode | regular | follow | steps | steps drives an explicit list instead of planning |
steps | array | {instruction, url?} - required when mode is steps |
A 422 means the recorder read the prompt and judged it not actionable. The response carries
rejected: true and usually a suggestion for a rewrite - show it rather than retrying blindly.
Attachments and file uploads are dashboard-only; the API takes JSON.
Check on it
GET /v1/recordings/:jobId
{
"jobId": "video_recording_...",
"status": "completed",
"aborted": false,
"partial": true,
"partialReason": "The export dialog needed a paid plan, so the last two steps aren't shown.",
"duration": "547s",
"completedAt": "2026-08-12T21:04:00.000Z"
}
Two failure shapes matter, and they are not the same thing:
aborted- the agent stopped and there is no usable video. A paywall, a missing permission, a UI that doesn't exist.errorholds its reason.partial- a video exists, but it doesn't show the whole flow. The steps that worked were recorded rather than thrown away.partialReasonsays what's missing.
Never present a partial recording as a finished tutorial. status is completed in both
cases; the flags are what tell them apart.
duration is the agent's wall-clock runtime, not the video's playback length.
When the agent gets stuck on a value
POST /v1/recordings/:jobId/input with {"value": "..."}
Some flows pause for something only a person has - a one-time code, a 2FA challenge, a security answer. The job waits, and this hands the value over.
Ask a human for it. Don't guess, and don't forward a credential that wasn't given for this purpose.
Get the file
GET /v1/recordings/:jobId/download
{ "downloadUrl": "https://...", "expiresIn": 3600 }
A time-limited URL, not the bytes - fetch it directly. 409 if the job hasn't completed.
List and delete
GET /v1/recordings - cursor-paginated, filterable by
status.
DELETE /v1/recordings/:jobId removes the job from the list. A video already imported from it is
a separate object and is untouched.
Saved logins
GET /v1/recorder-sessions · PATCH /v1/recorder-sessions/:domain ·
DELETE /v1/recorder-sessions/:domain
To record a site behind a login, the recorder can keep the session and reuse it next time. Sessions are keyed by domain - one per domain per workspace - and expire on their own.
The stored cookies never leave Vidocu. The API reports that a session exists, when it expires, and its setup instructions:
{
"sessions": [
{
"domain": "app.example.com",
"setupPrompt": "Switch to the Acme workspace and close the welcome banner",
"createdAt": "2026-08-01T09:12:00.000Z",
"updatedAt": "2026-08-20T14:03:00.000Z",
"expiresAt": "2026-09-19T14:03:00.000Z"
}
]
}
Setup instructions
setupPrompt is a short set of steps the recorder performs on that site before every recording
and screenshot, off camera - switching to the right workspace, dismissing a welcome banner,
opening the demo account. It is part of the session, so it applies to recordings started from the
dashboard, the API, and Pulse screenshots alike. null when unset.
PATCH /v1/recorder-sessions/:domain with { "setupPrompt": "..." } sets it; { "setupPrompt": null } clears it. Up to 2000 characters. Returns the updated session
(domain, setupPrompt, updatedAt, expiresAt), or 404 when there is no saved login for the
domain. Requires recordings:write and a role that can edit.
A recording request that carries its own setupPrompt wins over the session's for that one job;
the session's is not changed.
Billing
Charged per minute of finished video when the job completes, with a 1-minute minimum that covers the fixed planning cost every job pays. A balance check runs before the job starts, so one that could never be paid for doesn't begin.
Failed and aborted jobs are free. A partial recording produced a video, so it is charged for what it produced.
Errors
| Status | Code | Cause |
|---|---|---|
| 402/403 | limit_exceeded | Free plan, or not enough balance to start |
| 404 | not_found | No such recording in this workspace |
| 409 | conflict | Download requested before the job finished |
| 422 | validation_error | The recorder judged the prompt not actionable |
| 429 | rate_limit_exceeded | Two recordings are already running for this workspace |