Clean by default
Consent walls, sign-in modals, newsletter popups and paywall scrims are removed before capture. Known CMPs are declined properly; anything else is caught by shape — fixed, painted, high z-index, covering the page.
Screenshot API
A screenshot API that removes consent walls, sign-in modals and paywall overlays before it captures. Most screenshot APIs succeed 93% of the time and return something usable 69% of the time — we measured it, and fixed it.
Left is the page as it loads. Right is what the API returns. No signup, no key.
We benchmarked 29 URLs across headless, stealth and headful browsers, from both a residential line and a datacenter address. Every number on this page came out of that run — method, findings and the parts that went against us.
Consent walls, sign-in modals, newsletter popups and paywall scrims are removed before capture. Known CMPs are declined properly; anything else is caught by shape — fixed, painted, high z-index, covering the page.
Declining on your behalf for a throwaway render is defensible. Agreeing on your behalf is not. Reject buttons that are really paywall funnels are detected by their own label and skipped in favour of hiding.
The examples on this page work pasted, with no key and no account — 40 renders an hour against your address. A free key raises that, and signed URLs let you drop a render into an <img src> without publishing a credential to every browser that loads the page.
Viewport, device pixel ratio, full-page, PNG / JPEG / WebP, quality, dark mode, locale, timezone, element waits and delays. Sensible defaults so the simple call stays one line.
An MCP server, an OpenAPI description, llms.txt and a machine-readable api-catalog. Your agent can discover and call it without you writing a wrapper first.
The same endpoint family prints a page as well as photographing it, on the plan you already have — a PDF costs one render, not a second subscription. Suppression matters more there: a consent wall does not cover a PDF, it collapses it to a single page.
Some pages are behind bot protection and no browser trick gets past them — we tested that too, and say so rather than pretending. You get a clear error, not a picture of a challenge page.
POST /v1/render
→ image/png# No key needed. Paste this as it is.
curl -X POST https://shots.rendershed.com/v1/render \
-H "Content-Type: application/json" \
-d '{"url": "theguardian.com/international"}' \
-o shot.png
# A free key raises the limit from 40 renders an hour to 100 a month
# and keeps working from any address:
# -H "X-API-Key: $RENDERSHED_KEY"const res = await fetch("https://shots.rendershed.com/v1/render", {
method: "POST",
headers: {
"Content-Type": "application/json",
// Optional. Without it you are on the anonymous tier.
...(process.env.RENDERSHED_KEY && {
"X-API-Key": process.env.RENDERSHED_KEY,
}),
},
body: JSON.stringify({
url: "https://www.booking.com",
width: 1440,
response: "json", // base64 instead of raw bytes
}),
});
const png = Buffer.from(await res.arrayBuffer());import os, requests
# The header is optional; leave it out to use the anonymous tier.
res = requests.post(
"https://shots.rendershed.com/v1/render",
headers={"X-API-Key": os.environ.get("RENDERSHED_KEY", "")},
json={"url": "https://www.bbc.com/news", "format": "jpeg", "quality": 80},
timeout=90,
)
open("shot.jpg", "wb").write(res.content)<!-- signed server-side; no key reaches the browser -->
<img src="https://shots.rendershed.com/v1/render?url=https%3A%2F%2Fstripe.com&width=1200&sig=..."
width="1200" height="750" alt="stripe.com" loading="lazy">
| Name | Type | Default | Description |
|---|---|---|---|
url | string | required | The page to render. http and https only. |
device | enum | — | iphone, android or ipad. Sets the viewport, the user agent and the touch flags together, so a site that sniffs the agent still serves its mobile page. Overrides width and height. |
width | int | 1440 | Viewport width, 200–3840. Ignored when device is set. |
height | int | 900 | Viewport height, 200–4320. |
dpr | float | 1 | Device pixel ratio, up to 3. |
full_page | bool | false | Capture the whole document, not just the viewport. |
format | enum | png | png, jpeg or webp. |
quality | int | — | 1–100, for jpeg and webp. |
overlay_mode | enum | dismiss | off, hide or dismiss. |
block_ads | bool | true | Drop known ad and tracker requests. |
dark_mode | bool | false | Render with prefers-color-scheme: dark. |
wait_for_selector | string | — | Wait for a CSS selector before capture. |
delay_ms | int | 0 | Extra settle time, up to 10000. |
locale | string | en-US | Browser locale. |
timezone | string | UTC | IANA timezone. |
The same page printed rather than photographed. A3 through tabloid, landscape, margins, scale, page ranges and page numbers — on the key and the allowance you already have. It runs on the key and the allowance you already have — HTML to PDF API.