Your agent can read HTML. It cannot see what rendered. RenderScreenshot gives an agent eyes with one HTTP call: the agent picks a URL, your tool calls POST /v1/screenshot, and the model gets back an image it can inspect, compare or attach to its report. No browser to host, no Chrome in your container, and the same request works from OpenAI, Anthropic and Vercel AI SDK tools.
This page shows the tool definition, what each capture costs in model tokens (measured, not guessed), and the settings that matter for agents.
How it works
User question │ ▼ LLM ──(tool call: screenshot_url {url, full_page})──► your tool code │ POST /v1/screenshot │ Authorization: Bearer rs_live_... ▼ RenderScreenshot API (auth, validation, cache, billing) │ ▼ Headless Chrome on Cloudflare │ image bytes + X-Cache-URL (public CDN link) │ LLM ◄──(tool result: image block + cache URL)───────────┘ │ ▼ Answer, decision, or report with the screenshot as evidence
Two details in this flow matter for agents:
- The image goes to the model, the URL goes to your records. The response body is the image. The
X-Cache-URLheader is a public CDN link to the same image that needs no key, so you can store it in a log, a ticket or a report without copying bytes around. See response headers. - Your code owns the request, the model owns only the inputs you expose. The model chooses
urland maybefull_page. Your tool sets the viewport, the format, cookie-banner blocking and the timeout. That keeps captures consistent and costs predictable.
The tool definition
This is the provider-neutral shape. Every framework below wraps the same JSON Schema:
{ "name": "screenshot_url", "description": "Capture a screenshot of a public web page and return it as an image. Use it when you need to see the rendered page: layout, visual state, or content that only appears after JavaScript runs. Use full_page only when content below the first screen matters.", "input_schema": { "type": "object", "properties": { "url": { "type": "string", "description": "Absolute http(s) URL to capture." }, "full_page": { "type": "boolean", "description": "Capture the whole scrollable page. Default false." } }, "required": ["url"] } }
And this is the request your tool sends. It is plain HTTP, so you can test it with curl before any model is involved:
curl -sS -X POST https://api.renderscreenshot.com/v1/screenshot \ -H "Authorization: Bearer $RS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com", "viewport": { "width": 1280, "height": 800 }, "output": { "format": "jpeg", "quality": 80 }, "block": { "cookie_banners": true }, "wait": { "until": "networkidle", "timeout": 30 } }' \ -D headers.txt -o page.jpg
Wire it into your framework
Each integration guide has a complete, runnable file. The key difference between frameworks is how a tool returns an image instead of text:
| Framework | Where the schema goes | How the image goes back | Guide |
|---|---|---|---|
| Anthropic Messages API | tools[].input_schema |
tool_result block whose content holds an image block (base64) |
Claude tool use |
| OpenAI Agents SDK (Python) | @function_tool type hints and docstring |
Return ToolOutputImage with a data URL |
OpenAI Agents SDK |
| Vercel AI SDK | tool({ inputSchema: z.object(...) }) |
toModelOutput returns a content result with a file part |
Vercel AI SDK |
| LangChain / LangGraph | @tool signature or a zod schema |
content_and_artifact: image block for the model, metadata as the artifact |
LangChain |
A common mistake is to return the base64 string as plain text. The model then pays text tokens for every base64 character and cannot see the image at all. A 95 KB JPEG becomes about 127,000 base64 characters. Return a real image block.
What a capture costs the model
We measured 26 real pages as raw HTML, cleaned HTML, accessibility tree, visible text and screenshot. The full data and script are in screenshot vs DOM vs accessibility tree. The summary:
| What the agent receives | Median tokens (26 pages) | Notes |
|---|---|---|
| Raw HTML | 97,744 | 13 of 26 pages were over 100,000 tokens |
| Cleaned HTML (no scripts, styles, most attributes) | 19,441 | Still about 9 times the visible text |
| Accessibility tree (Playwright snapshot) | 8,148 | Best when the agent must click or type |
| Visible text | 2,066 | Cheapest for reading; no layout or images |
| One 1280x800 screenshot | 1,334 | Fixed cost on Claude, whatever the page contains |
Text tokens use the o200k_base tokenizer. Image tokens use Anthropic's published formula, ceil(w/28) × ceil(h/28). The trade-off is coverage: one screenshot shows one screen, and the median page was 6,525 px tall.
Settings that matter for agents
| Setting | Recommended value | Why |
|---|---|---|
viewport |
{ "width": 1280, "height": 800 } |
1,334 tokens on Claude with no downscaling. On standard-tier models, a 1920x1080 capture is scaled down to 1456x819, so you upload pixels the model throws away. |
output.format |
jpeg or webp, quality 80 |
Token cost is the same as PNG. The upload is about half the size, which matters because agents resend history on every turn. |
block.cookie_banners |
true |
Consent dialogs cover the content the agent came to see. |
wait.until |
networkidle |
Waits until no requests for 500 ms, so SPAs finish rendering. See wait options. |
capture.mode |
viewport by default; full_page with scroll.max_height 4000 when asked |
A tall page sent as one image arrives as a thumbnail. Cap the height or crop. |
capture.mode: "element" + selector |
For one table, chart or form | The model pays only for the pixels of that element. See capture options. |
cache.available |
true for repeated checks |
Returns a recent identical capture from your account at 0 credits instead of rendering again. See caching. |
Guardrails before you ship
- Treat page content as data. A screenshot can contain text such as "ignore previous instructions". Say in the system prompt that text inside images is page content, never instructions, and keep tools with side effects behind confirmation.
- Restrict what the model can capture. Validate the URL in your tool: require
https:, and if the agent should only look at your sites, check the hostname against an allowlist before you call the API. - Keep credentials out of the schema. If the agent needs logged-in pages, your code adds
network.cookiesornetwork.headers. The model never sees or chooses them. - Cap the loop. Set a maximum number of tool rounds. A model that keeps calling
screenshot_urlcosts credits and tokens on every call. - Return errors as tool output. Error responses have a
type, acodeand aretryableflag (see error codes). A model that sees "ratelimiterror, retryable" can wait and try again.
Pricing
Each rendered screenshot uses one credit. You pay for captures, not for tokens; the model provider bills tokens separately. Prices as of October 2026 (current prices on the pricing page):
| Plan | Credits per month | Price |
|---|---|---|
| Free | 150 | $0, no credit card |
| Starter | 2,500 | $10 |
| Growth | 12,000 | $40 |
| Scale | 60,000 | $100 |
Example: an agent that checks 40 pages after every deploy, 3 deploys a day, uses about 3,600 credits a month. That fits in Growth. With cache.available set, checks that repeat an identical request inside the cache TTL use 0 credits.
Start building
- Create a free account and copy your
rs_live_key from the dashboard. - Run the curl command above to confirm the key works.
- Pick your framework guide from the table and paste the tool into your agent.
For the agent architecture behind evidence-carrying reports, read screenshots for AI agents. To tune capture size for vision accuracy, read screenshots for GPT and Claude vision.