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.

MCPdownload_asset.mcp.jsonjson
// MCP tool call — server "twin-browser"
{
  "tool": "download_asset",
  "arguments": {
    "url": "https://example.com/logo.svg"
  }
}
POST /api/v1/downloadrequest.shbash
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.

Parameters accepted by download_asset
ParameterTypeWhat it does
url*stringDirect URL of the asset. Its origin must be a well-formed http(s) target.
referrerstringOptional Referer header — some CDNs hotlink-check this before serving an asset.
accountstringWhich stored login's session to use, when several are kept for this host (a label from list_accounts).
maxBytesnumberByte ceiling before refusing the download. Default 10 MB, hard-capped at 25 MB.
proxystringYour own egress proxy URL.
stealthbooleanRoute through the stealth fleet, for an asset host that bot-walls plain requests. Pro/Enterprise plan required. Default off.

Returns

response.jsonjson
// 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 card

Which one

When a different tool is the right call.

The honest answer is often the neighbouring tool. These are the trades.

extract

extract 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."

extract
screenshot

screenshot 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.

screenshot

Questions

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.