Observation & data
Get the actual file, not just a reference to it
Fetch a logo, image, PDF, or other document as raw bytes — a single HTTP GET through the browser's own request context, so a saved session's cookies and an in-flight proxy apply exactly as a real page load would.
download_asset
What it is
The job: Turn a URL you already have into the bytes it points at.
extract reads a page and hands back the `src` of an image or the `href` of a PDF link — a reference, not the file. screenshot renders a page visually. Neither one gets you the asset's actual bytes. download_asset is the missing third leg: point it at a direct asset URL and it fetches the file itself, base64-encoded in the response.
It is a single HTTP GET through Playwright's own request context, not a page render — no navigation, no readiness wait, no LLM call, so it is fast and cheap. Because the request goes through the SAME browser context a run would use, a saved session's cookies and any proxy you pass apply exactly as they would to a real page load.
That session behavior is the useful part: when this tenant has a captured session for the asset's host — from connect_account, the capture extension, or a prior login run — it is applied automatically, with no flag to remember. A document that sits behind a login (an account export, an invoice PDF) downloads without a fresh sign-in. The response reports `sessionUsed` so you can tell which path was taken.
There is a byte ceiling, on purpose: 10 MB by default, raisable to 25 MB via `maxBytes`. Over the cap you get a clear "asset_too_large" error naming the actual size — never a silently truncated file.
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": "download_asset",
"arguments": {
"url": "https://example.com/logo.svg"
}
}curl -X POST https://twin-browser.com/api/v1/download \
-H "Authorization: Bearer $TWIN_API_KEY" \
-H "content-type: application/json" \
-d '{"url":"https://example.com/logo.svg"}'This fetches whatever URL you give it directly — it does not navigate a page first. If the asset needs a Referer to pass a hotlink check, or its URL is relative, resolve it (e.g. with extract or observe_page) before calling this.
| Parameter | Type | What it does |
|---|---|---|
| url* | string | Direct URL of the asset. Its origin must be a well-formed http(s) target. |
| referrer | string | Optional Referer header — some CDNs hotlink-check this before serving an asset. |
| account | string | Which stored login's session to use, when several are kept for this host (a label from list_accounts). |
| maxBytes | number | Byte ceiling before refusing the download. Default 10 MB, hard-capped at 25 MB. |
| proxy | string | Your own egress proxy URL. |
| stealth | boolean | Route through the stealth fleet, for an asset host that bot-walls plain requests. Pro/Enterprise plan required. Default off. |
Returns
// MCP (and REST, by default)
{ "data": "<base64>", "mime": "image/svg+xml", "bytes": 4821,
"status": 200, "url": "https://example.com/logo.svg",
"sessionUsed": false, "credits_charged": 1 }
// REST with an Accept header matching the asset's mime (or
// "application/octet-stream"): the raw file bytes instead, with the
// charge in the x-credits-charged response header.What it costs
1 credit
Flat, like screenshot and observe_page — a single GET with no page render and no LLM call to meter. maxBytes is the abuse ceiling rather than a price curve.
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.
extractextract reads a page and gives you the asset URL (a `src` or `href`); download_asset turns that URL into the actual bytes. Use them in sequence for "get me the file this page links to."
extractscreenshotscreenshot renders a page as pixels for a human or vision model to look at. download_asset fetches a file that already exists as a resource — a logo, a PDF — with nothing to render.
screenshotQuestions
download_asset, answered.
- Can this download a file behind a login I have not captured a session for?
- No — it applies whatever session Twin Browser already has for that host, it does not sign in itself. If nothing is stored yet, send the user through connect_account first (or capture one with the extension), then re-run the download.
- What happens to a PDF or ZIP over the byte cap?
- A clean 413 with code "asset_too_large" and the actual size the server declared (or the buffered size, if it never declared one) — never a truncated file. Raise maxBytes up to the 25 MB hard cap if you genuinely need the full asset.
Keep going
The rest of the tool set.
extractGet data off a page in the shape your code already expects.
screenshotGet one honest image of a page, without catching it mid fade-in.
list_accountsAnswer “can I get into this site, and as whom?” before starting a run.
connect_accountGet logged into a site that an agent is not going to be allowed to log into.