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
Your result will appear here.
Enter a URL above, or pick one of the example pages.
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
- Images only. PNG, JPEG or WebP. For the page as a PDF, the PDF API returns it from the same kind of request, for 1 credit.
- 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 or fill a form. A page behind a login is captured signed in with an auth profile.
- Public addresses 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
Yes. With no options you get the whole scrollable page as a PNG, up to 16,384 px tall, with lazy-loaded images scrolled into view first. Set full_page to false for the viewport only.
No. Every screenshot costs 1 credit, whichever options you use.
Read the X-Result-Url response header. It is a signed link to the image that needs no API key and stays valid for 30 days, so it goes straight into an img tag.
Yes — set screenshot_options.selector to a CSS selector. The first match is captured; a selector that matches nothing fails the request and costs nothing.
Yes, from /pdf: send the same URL there and the whole rendered page comes back as a PDF, for 1 credit. The screenshot API itself returns PNG, JPEG or WebP images.
Send page_options.block_cookie_banners: true. The banners of the major consent-management providers are removed from the page before capture, without clicking anything.
Yes. Upload a signed-in browser's state once as an auth profile and send auth_profile with the request: the dashboard, account page or admin screen is captured as that user sees it, for the same credit.
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.