Skip to main content

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.

FieldTypeDescription
promptstringWhat the recording should show, up to 50,000 characters. Required
namestringDisplay name in lists, up to 200 characters. Absent = the prompt is shown. Same field PATCH renames
urlstringWhere to start
devicedesktop | mobileViewport to record in
pacingrelaxed | standard | briskReplay speed of the finished video
maxDurationSecnumberMax length of the finished video in seconds, up to 1800. 0 or absent means no limit
removeLoadingbooleanCut the time spent waiting for pages to load: the first load, navigations, and loads after a click. The video jumps straight to each loaded screen. Default false
moderegular | follow | stepssteps drives an explicit list instead of planning
stepsarray{instruction, url?} - required when mode is steps
sessionIdstringThe saved login to start signed in with, by id from GET /v1/recorder-sessions. Omit it to use the site's default session

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.

With removeLoading, Vidocu cuts the waits the recorder itself sees, from the moment a page starts loading until its network goes quiet. A spinner that keeps turning after the network has gone quiet stays in the video. Waits longer than 6 seconds are sped up into a short time-lapse either way.

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. error holds its reason.
  • partial - a video exists, but it doesn't show the whole flow. The steps that worked were recorded rather than thrown away. partialReason says 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, rename and delete​

GET /v1/recordings - cursor-paginated, filterable by status.

PATCH /v1/recordings/:jobId with {"name": "Create a project folder"} gives a recording a display name. Every recording response carries name (null when unset), and the dashboard's recordings list shows it instead of the prompt. Send null or "" to clear it. Up to 200 characters. The prompt never changes. Needs recordings:write and a role that can edit.

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/:session · DELETE /v1/recorder-sessions/:session

To record a site behind a login, the recorder can keep the session and reuse it next time. Sessions expire on their own.

A site can have several saved sessions, for example "Sandbox" and "Admin user". Each one has:

FieldDescription
idUse it in the path below and as sessionId when you start a recording
nameA label. Sessions saved before names existed show their domain
isDefaultExactly one session per site is the default. A recording that names no sessionId uses it
createdByUser id of whoever saved it. null for older sessions
contextWho this login is and what it sees. null when unset. See Account context

The stored cookies never leave Vidocu. The API reports that a session exists, when it expires, how long it is kept, its setup instructions and its context:

{
"sessions": [
{
"id": "6703a1f4c2e9b81d4f0a7c21",
"domain": "app.example.com",
"name": "Sandbox",
"isDefault": true,
"createdBy": "64f0c2a9e1b7d3a5c8f91e02",
"setupPrompt": "Switch to the Acme workspace and close the welcome banner",
"context": "Teacher account: manages classes, assigns lessons, sees grades",
"ttlDays": 30,
"createdAt": "2026-08-01T09:12:00.000Z",
"updatedAt": "2026-08-20T14:03:00.000Z",
"expiresAt": "2026-09-19T14:03:00.000Z"
}
]
}

Sessions are listed most recently used first. updatedAt is when the login was last refreshed.

Pick a session​

:session in the path is a session id. A domain still works too, and means that site's default session.

To record with a session that isn't the default, pass its id as sessionId to POST /v1/recordings. If that session no longer exists, the request returns 400. Nothing switches to another session behind your back.

Rename it, or make it the default​

PATCH /v1/recorder-sessions/:session with { "name": "Admin user" } renames it. Up to 80 characters. "" resets it to the domain.

{ "isDefault": true } makes it the site's default. Only true is accepted: a site always has a default, so to change it, make another session the default.

Send any mix of name, isDefault, setupPrompt, context and ttlDays, at least one. A field you leave out stays as it is. Returns the updated session (id, domain, name, isDefault, createdBy, setupPrompt, context, ttlDays, updatedAt, expiresAt), or 404 when there is no such session. Requires recordings:write and a role that can edit.

Delete a session​

DELETE /v1/recorder-sessions/:session returns { "deleted": true, "id": "...", "domain": "..." }. Requires recordings:write and a role that can delete.

By domain, it only works when the site has one session. With several, it returns 409 and lists them in sessions (id, name, isDefault), so delete by id instead. That way you never delete one you didn't pick.

Delete the default, and the most recently used remaining session for that site becomes the new default. Delete the last one, and recordings on that site have to sign in again.

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/:session with { "setupPrompt": "..." } sets it; { "setupPrompt": null } clears it. Up to 2000 characters. Each session has its own, so "Sandbox" and "Admin user" on the same site can start from different places.

A recording request that carries its own setupPrompt wins over the session's for that one job; the session's is not changed.

Account context​

context says who the login is and what it can see and do. Useful when one product has very different logins, for example a student and a teacher:

{ "context": "Teacher account: manages classes, assigns lessons, sees grades" }

It only describes the account. The recorder never performs it as steps (that is what setupPrompt is for). Pulse uses it to write docs for the right audience, and a recording that uses the session reads it as background about the account.

PATCH /v1/recorder-sessions/:session with { "context": "..." } sets it; { "context": null } clears it. Up to 2000 characters. Signing in again, or a recording refreshing the login, never changes it. null when unset.

How long a session is kept​

ttlDays is how many days a session is kept after it was last used. Every recording or screenshot that uses the session pushes expiresAt forward again. The default is 14. You can set it to 30, 90, 180 or 365.

PATCH /v1/recorder-sessions/:session with { "ttlDays": 90 } changes it. You can send it alone or with other fields, and a field you leave out stays as it is. expiresAt is then counted from the session's last use (updatedAt), not from now. So if you shorten it below the session's age, the session expires right away. Any other value returns 400.

A longer ttlDays only stops Vidocu from forgetting the login. If the site itself signs people out after a week, the session still stops working after a week.

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.

To cap the cost of a run, set maxDurationSec. The agent plans to fit that length, the replay speeds up if the plan runs over, and the finished video is cut at it, so a job is never charged for more than that many seconds (the 1-minute minimum still applies).

Errors​

StatusCodeCause
402/403limit_exceededFree plan, or not enough balance to start
400validation_errorInvalid input, or the sessionId no longer exists
404not_foundNo such recording or saved session in this workspace
409conflictDownload requested before the job finished, or a session delete by domain when the site has several
422validation_errorThe recorder judged the prompt not actionable
429rate_limit_exceededTwo recordings are already running for this workspace