Record HTML to video
record_htmlRecord a web page or HTML5 creative (banner, ad, animation, landing page) to a video: MP4 (default), WebM or GIF. Returns the finished recording with a video link.
Input: either url (a public http(s) page; localhost and private networks are out of reach) or html (a complete single-file HTML document you wrote, published at an unlisted public URL and recorded from there). Set width and height to the creative's size (e.g. 300×250, 728×90, 1080×1920, 1920×1080) and durationSec to how long it runs.
Waiting: the call waits up to waitSec (default 45 s) for the video. If it isn't done by then, you get the recording with status queued or running; it keeps going. Call get_recording with its id and waitSec to wait for it; don't call record_html again for it.
Retries are safe: identical calls within 10 minutes return the same recording. After changing the creative behind the same url, pass a new revision to record it again. A failed recording is never reused: call again once you've fixed the cause.
Trim markers: by default the video starts at the page's load event and lasts durationSec. To capture exactly the animation, the page can mark it. The recorder defines two global functions in every frame (iframes included):
trim_start(): call it once when the assets are loaded, just before the animation starts. The video starts there.
trim_end(): call it once from the animation's completion callback (e.g. GSAP onComplete, the last animationend). The video ends there and durationSec becomes the maximum. Guard both so the page still works in a normal browser: // assets loaded, just before the animation starts: if (typeof trim_start === 'function') trim_start(); // in the animation's completion callback: if (typeof trim_end === 'function') trim_end(); Never call the two right after each other: that marks an empty clip. With sync "markers" the recording fails instead of falling back to the load event when trim_start() isn't called within markerWaitSec (default 10 s). report.anchor says "trim_start" when the start marker was used.
Links: video.url is signed and valid for 1 hour (get_recording mints a fresh one). pageUrl is the recording's page in the web app, for a person to open later (they sign in).
Limits: the account's limits apply (length, size, fps, recordings at a time and per day); estimate_recording checks a request without recording. Errors say what to change: fix it and call again.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| crf | No | Quality for mp4 and webm, from 10 (best, largest) to 35 (smallest). Not together with bitrateMbps; not for gif. | |
| fit | No | How the frame fills outputSize: fill (stretch), contain (letterbox in background) or cover (crop to fill). | |
| fps | No | Frame rate: one of 15, 23.976, 24, 25, 29.97, 30, 59.94, 60 (default 30). For gif, a whole number from 1 to 30. | |
| url | No | Public http(s) URL of the page or creative to record. The recorder runs on the internet: localhost and private networks are out of reach. Pass url or html, not both. | |
| crop | No | Record only this region of the viewport: { x, y, width, height } in pixels, even values, inside the viewport. | |
| html | No | A complete HTML document to record instead of a url, e.g. a banner you just wrote. One file: inline the CSS and JavaScript, and load images, fonts and libraries from public https URLs or data: URIs. It is published at an unlisted public URL and recorded from there. | |
| loop | No | gif only: whether the gif loops. | |
| sync | No | How trim markers are used: auto (default: markers when the page calls trim_start(), else the load event), load (ignore markers) or markers (fail when trim_start() is not called within markerWaitSec). | |
| audio | No | Record the page’s audio too. Not for gif. | |
| width | Yes | Viewport width in CSS pixels: even, 16–7680. Use the creative’s size, e.g. 300 for a 300×250 banner or 1920 for a full HD page. | |
| format | No | mp4 (default, H.264), webm or gif. | |
| height | Yes | Viewport height in CSS pixels: even, 16–7680. | |
| startAt | No | Where the video starts: "load" (default: the load event, or the first trim_start() call) or that many milliseconds after it (0–120000). | |
| waitSec | No | How long to wait for the finished video, in seconds (0–45, default 45). The recording keeps going after the call returns. | |
| renderer | No | auto (default), cpu or gpu. Leave it on auto. | |
| revision | No | Any label that changes when the creative changes. Identical calls within 10 minutes return the same recording; after you change the creative behind the same url, pass a new revision to record it again. | |
| background | No | Letterbox colour for fit: contain, as #rrggbb. | |
| outputSize | No | Scale the video to { width, height } (even values); see fit. | |
| bitrateMbps | No | A target bitrate in Mbps (1–100) instead of crf, for platforms with a bitrate spec (e.g. DOOH). Not for gif. | |
| bitrateMode | No | vbr (default) or cbr. Needs bitrateMbps. | |
| durationSec | Yes | Length of the video in seconds (1–300; your account limit applies). With trim_end() it is the maximum. | |
| pixelFormat | No | yuv420p (default; plays everywhere), yuv422p or yuv444p. | |
| markerWaitSec | No | How long to wait for trim_start() after load, in seconds (0–60, default 10). | |
| markerLatencyMs | No | Overrides the measured delay between a marker call and the frame it marks (0–1000 ms). Rarely needed. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| error | Yes | ||
| video | Yes | ||
| report | Yes | ||
| status | Yes | ||
| pageUrl | Yes | ||
| request | Yes | ||
| progress | Yes | ||
| renderer | Yes | ||
| createdAt | Yes | ||
| finishedAt | Yes |