Screenshot API

Screenshots of the page. Not the cookie banner.

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.

overlay_mode=off overlay_mode=dismiss
93%renders succeedacross a 29-URL benchmark
69%are actually usablethe gap nobody quotes
1 / 29blocked by bot protection7 ruined by consent walls
~2smedian renderp50, viewport capture

See the difference

Left is the page as it loads. Right is what the API returns. No signup, no key.

overlay_mode=off raw
overlay_mode=dismiss clean

The gap nobody quotes

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.

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.

It never clicks Accept

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.

No signup to try it

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.

The controls you expect

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.

Built for agents

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.

PDF on the same key

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.

Honest about limits

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.

One call 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">

Parameters

NameTypeDefaultDescription
urlstring requiredThe page to render. http and https only.
deviceenum 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.
widthint 1440Viewport width, 200–3840. Ignored when device is set.
heightint 900Viewport height, 200–4320.
dprfloat 1Device pixel ratio, up to 3.
full_pagebool falseCapture the whole document, not just the viewport.
formatenum pngpng, jpeg or webp.
qualityint 1–100, for jpeg and webp.
overlay_modeenum dismissoff, hide or dismiss.
block_adsbool trueDrop known ad and tracker requests.
dark_modebool falseRender with prefers-color-scheme: dark.
wait_for_selectorstring Wait for a CSS selector before capture.
delay_msint 0Extra settle time, up to 10000.
localestring en-USBrowser locale.
timezonestring UTCIANA timezone.