Observation & data
Capture a page once it has finished painting
A single PNG or JPEG of a URL — full page, viewport, or one CSS selector — captured only after webfonts resolve, images decode, entrance animations play out and two frames come back byte-identical.
screenshot
What it is
The job: Get one honest image of a page, without catching it mid fade-in.
The naive screenshot fires at the load event, which on a modern page is well before the page looks finished: the hero is still fading in, the webfont has not swapped, the images have not decoded. The result is a picture of a page nobody ever sees. This capture waits for visual completion instead — load, a bounded network idle, fonts resolved, images decoded, finite CSS and Web animations played out, and two byte-identical probe frames, which also catches requestAnimationFrame and canvas work that the platform reports nothing about.
You can scope the capture: `fullPage` for the whole scrollable document, a `selector` for exactly one element, or neither for the viewport. Encoding is PNG by default; pass type "jpeg" with a quality for a far smaller payload, which is the right pick when the image is going into a vision model rather than onto a screen.
No action is taken, no goal is run, and no model is called. Over MCP the image comes back as base64 with its mime type and byte length; the REST endpoint returns the image bytes directly.
The call
Call it exactly like this.
Copied from the tool's registration and the route handler — not paraphrased.
// MCP tool call — server "twin-browser"
{
"tool": "screenshot",
"arguments": {
"url": "https://example.com",
"fullPage": true,
"type": "jpeg",
"quality": 70
}
}curl -X POST https://twin-browser.com/api/v1/screenshot \
-H "Authorization: Bearer $TWIN_API_KEY" \
-H "content-type: application/json" \
-d '{"url":"https://example.com","fullPage":true,"type":"jpeg","quality":70}'| Parameter | Type | What it does |
|---|---|---|
| url* | string | The URL to capture. Its origin must be a well-formed http(s) target. |
| fullPage | boolean | Capture the full scrollable page. Default false — viewport only. |
| selector | string | CSS selector to capture just one element instead of the page. |
| type | "png" | "jpeg" | Encoding. png (default) is lossless; jpeg is lossy and far smaller. |
| quality | number | JPEG quality 1–100, default 70. Ignored for png. |
| settle | boolean | Wait for the page to be visually finished before capturing. Default true; false captures at the load event. |
| settleMs | number | Ceiling in milliseconds on the readiness wait (default 8000). A quiet page never reaches it; this only bounds a page that never stops moving. |
| animations | "disabled" | "allow" | disabled (default) fast-forwards finite animations to their end state and freezes infinite ones at capture time. allow films whatever frame is live. |
| waitMs | number | Extra wait in milliseconds applied AFTER the readiness settle, for something only you know about. |
| proxy | string | Your own egress proxy URL. |
| blockAssets | boolean | Abort image/media/font requests. Default OFF for screenshots, so visuals are kept. |
Returns
// MCP
{ "image": "<base64>", "mime": "image/jpeg", "bytes": 184203,
"fullPage": true, "selector": null, "url": "https://example.com", "status": 200,
"settle": { /* what the readiness gate observed */ } }
// REST: the image bytes (image/png or image/jpeg).
// The charge is in the x-credits-charged response header.What it costs
1 credit
Flat, and there is no LLM cost to meter — a screenshot takes no action and runs no model. The charge is reported in the x-credits-charged header on the REST response.
See the full rate cardWhich one
When a different tool is the right call.
The honest answer is often the neighbouring tool. These are the trades.
observe_pageIf the next thing you do is click something, take the element map, not the picture: an index is actionable and a pixel is not. Screenshot wins when a vision model is doing the reading, or when a human has to look at it.
observe_pagerecord_runOne frame versus the whole session. record_run captures a video of a run being performed; screenshot captures a page as it stands, with no run at all.
record_runQuestions
screenshot, answered.
- Why is my capture slower than a plain Playwright screenshot?
- Because it waits for the page to stop moving. The readiness gate resolves webfonts, decodes images, plays out finite animations and requires two byte-identical probe frames before capturing. A quiet page settles well under the ceiling; a page with a permanent animation hits settleMs and is captured anyway. Pass settle: false to get the old capture-at-load behaviour.
- PNG or JPEG for feeding a vision model?
- JPEG at quality 70. The payload is a fraction of the PNG and the detail loss is invisible to a model reading layout and text. Keep PNG when a human is going to inspect fine detail, or when you are diffing captures byte-for-byte.
Keep going