Screenshot API
Full-page screenshots of any URL, one flat price
The page as a browser draws it — the whole page by default, sized and cleaned up the way you need, with a link you can drop straight into an <img>.
By Roger Campos · Last updated: September 2026
TL;DR
POST a URL to /screenshot and get the whole rendered page back as a PNG — top to bottom, lazy images loaded, up to 16,384 px tall. screenshot_options change the viewport, pixel density, format, element, dark mode, hidden elements and CSS; every option is included in the same 1 credit.
Free plan, no credit card. 1,000 credits a month.
Try it now — no signup
Try your own URL
Your result will appear here.
Pick one of the pages above to get started.
The request
One POST, one bearer token
curl -X POST https://urlpipe.dev/screenshot \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/pricing", "sync": true, "screenshot_options": {"viewport_width":390,"device_scale_factor":2,"format":"webp"}, "page_options": {"block_cookie_banners":true}}'import requests
res = requests.post(
"https://urlpipe.dev/screenshot",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={"url": "https://example.com/pricing", "sync": True, "screenshot_options": {"viewport_width": 390, "device_scale_factor": 2, "format": "webp"}, "page_options": {"block_cookie_banners": True}},
)const res = await fetch("https://urlpipe.dev/screenshot", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({ url: "https://example.com/pricing", sync: true, screenshot_options: {"viewport_width":390,"device_scale_factor":2,"format":"webp"}, page_options: {"block_cookie_banners":true} }),
})$ch = curl_init("https://urlpipe.dev/screenshot");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer YOUR_API_KEY",
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode(["url" => "https://example.com/pricing", "sync" => true, "screenshot_options" => ["viewport_width" => 390, "device_scale_factor" => 2, "format" => "webp"], "page_options" => ["block_cookie_banners" => true]]),
]);
$response = curl_exec($ch);UklGRlq4AABXRUJQVlA4WAoAAAAgAAAARQUAhAUA…
X-Result-Url: https://urlpipe.dev/… (no key needed, valid 30 days)Defaults
What a screenshot captures by default
With no options, you get a full-page PNG: the whole scrollable document, not just the fold. The page is scrolled through first so lazy-loaded images are in the picture. The viewport is 1350 × 797 — a desktop window — so two captures of the same page line up and can be compared. The height follows the page up to 16,384 px; a longer page is captured down to that.
The body of the response is the image, Base64-encoded. Decode it to a file, or put it in a data: URI. If you only want to show it, you don't have to touch the bytes at all — see the image URL below.
screenshot_options
Every screenshot option
All optional, all included in the price. Out-of-range values are refused before anything is spent.
| Option | Values | What it does |
|---|---|---|
| full_page | true (default) / false | The whole page, or the viewport only (a #fragment URL scrolls to its anchor) |
| full_page_max_height | 100–16,384 px | The tallest the image may be |
| viewport_width | 320–1920, default 1350 | Window width — 390 gives a phone layout |
| viewport_height | 240–1080, default 797 | Decides the fold and anything sized to the screen |
| device_scale_factor | 1–3 | 2 renders a retina image, with the high-resolution assets |
| selector | CSS selector | Capture one element — a pricing table, a chart |
| format | png (default), jpeg, webp | WebP is usually far smaller for a long page |
| quality | 1–100, default 80 | JPEG and WebP only |
| omit_background | true / false | Transparent where the page sets no background (PNG, WebP) |
| dark_mode | true / false | Renders with prefers-color-scheme: dark |
| hide_selectors | up to 50 selectors | Hide a chat widget or promo bar in the image |
| styles | up to 20,000 characters | Your own CSS, injected before capture |
What the page waits for and what it loses happens in page_options: block_cookie_banners, block_ads, remove_selectors, wait_for_selector and delay. The difference from hide_selectors: page options remove elements from the page itself, so they are gone from the HTML and Markdown too; hidden selectors only change the image.
Image URL
Put the image straight into an <img>
Every screenshot response carries an X-Result-Url header: a signed link to the same image that needs no API key and stays valid for the 30 days the result is kept. Use it in a page you render, a digest email or a social card, with nothing to proxy. An async request gets the same link in its webhook payload as result_url.
const res = await fetch("https://urlpipe.dev/screenshot", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({ url: "https://example.com", sync: true }),
})
img.src = res.headers.get("X-Result-Url")Use cases
What people build with it
- Visual regression checks. The default viewport is fixed, so two captures of the same page line up pixel for pixel. Capture before and after a deploy with
max_age: 0and diff the images in your own pipeline. - Social cards and thumbnails.
selectorcaptures one element,stylesinjects CSS to tidy it, andviewport_widthwithfull_page: falsegives a fixed-size frame. - Evidence and archives. A full-page capture records what a page showed on a given day — a price, a claim, a policy. labels tie each capture to a case or client, and the result stays retrievable for 30 days.
- Mobile and dark-mode reviews.
viewport_width: 390anddevice_scale_factor: 2show the phone layout as a retina image;dark_modeshows the theme a site serves to users who prefer it. - Link previews. When a page has no
og:image, a viewport capture is the preview — see the metadata API.
Pricing
A flat price, whatever the options
A screenshot costs 1 credit — full page or viewport, PNG or WebP, 1× or 3×, with or without dark mode, CSS and hidden elements. The expensive dimensions are capped rather than metered: 16,384 px of height, a 20 MB image, 10 seconds each of delay and wait_for_selector. A capture you already took is reused for free while it is fresher than max_age, and a failed one costs nothing.
/scrape
Screenshot, metadata and Markdown from one visit
Link previews, archives and content audits usually need more than the picture. /scrape takes a list of operations and reads them all off one page load, so the screenshot, the metadata and the Markdown describe the same render:
{
"url": "https://example.com/blog/launch",
"operations": ["screenshot", "meta", "markdown"],
"screenshot_options": { "format": "webp", "full_page": false },
"page_options": { "block_cookie_banners": true }
}Each operation is billed as usual. Four screenshot options change how the page itself loads — viewport_width, viewport_height, device_scale_factor and dark_mode — so a screenshot with any of them takes its own visit, and the HTML beside it stays the page as it normally renders.
Limits
What it does not do
- No PDF output. Images only: PNG, JPEG or WebP.
- No video or scrolling captures. One still image per request.
- No delivery to your storage. The image comes back in the response, the webhook or the result URL; there is no S3 or bucket upload. Copy it where you need it.
- No interaction before capture. It can wait for an element, but not click, log in or fill a form.
- Public pages only. Private and intranet addresses are refused.
Pricing
What it costs
| Call | Credits | Free (calls/mo) | Starter (calls/mo) | Pro (calls/mo) | Scale (calls/mo) |
|---|---|---|---|---|---|
| /screenshot | 1 credit | 1,000 | 20,000 | 55,000 | 175,000 |
Cache hits and failed requests cost nothing. Paid plans are never cut off: past the allowance, extra credits are $1.50 per 1,000 credits. See every plan.
FAQ
Frequently asked questions
Are screenshots full-page by default?
Do options like retina, WebP or dark mode cost extra?
How do I show the screenshot without decoding Base64?
Can I capture just one element?
Can I get a PDF of the page?
How do I remove cookie banners from screenshots?
Make your first request in five minutes.
Free plan, no card. Confirm your email and your API key is live — you'll be making real requests in minutes.