URL Screenshot API for Developers
Build reliable URL screenshots with REST APIs, browser rendering controls, troubleshooting guidance, and a simpler ScreenshotNeo option.
Short answer: A URL screenshot API receives a page URL, renders its HTML, CSS and JavaScript in a browser, applies capture settings such as viewport and full-page mode, and returns an image or document. The basic workflow is:
- Authenticate with the provider.
- Send the URL and capture options.
- Wait for navigation and required page state.
- Save the returned PNG, JPEG, WebP or PDF.
- Inspect status and response headers, then retry only when the failure is transient.
This is useful for report generation, previews, QA, visual regression, archives and automated workflows that need repeatable page images without a person operating a browser.
What a screenshot API actually captures
A screenshot endpoint captures the rendered page, not just the URL’s source text. Browser Rendering services can process HTML and JavaScript before taking the image, and some accept either a URL or supplied HTML. Cloudflare documents URL and HTML input for its screenshot action (quick-action guide).
Capture settings change the result. Common controls include navigation timeouts, viewport dimensions, full-page mode, clipping, element selection and output format. Cloudflare’s API reference documents these controls (screenshot API reference).
Cloudflare Browser Rendering: a REST implementation
Cloudflare documents a REST endpoint and a Workers Binding route. The REST request uses an API token with the required Browser Rendering permission. Keep credentials in environment variables.
1. Set credentials and the endpoint
export CLOUDFLARE_ACCOUNT_ID="your-account-id"
export CLOUDFLARE_API_TOKEN="your-browser-rendering-token"
export CLOUDFLARE_SCREENSHOT_ENDPOINT="https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/browser-rendering/screenshot"
Confirm the current endpoint and token scope in Cloudflare’s documentation before deployment. Do not commit the token or assume it can access every site.
2. Capture a URL with cURL
curl --fail-with-body -X POST "$CLOUDFLARE_SCREENSHOT_ENDPOINT" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{
"url": "https://example.com",
"screenshotOptions": {
"fullPage": true,
"viewport": {"width": 1440, "height": 900}
}
}' \
-o page.png
Use the exact request schema shown in the current API reference. If your account’s response is JSON-wrapped rather than raw image bytes, parse the documented response and decode or download the returned image field.
3. Python with requests
import os
import requests
endpoint = os.environ["CLOUDFLARE_SCREENSHOT_ENDPOINT"]
headers = {
"Authorization": f"Bearer {os.environ['CLOUDFLARE_API_TOKEN']}",
"Content-Type": "application/json",
}
payload = {
"url": "https://example.com",
"screenshotOptions": {
"fullPage": True,
"viewport": {"width": 1440, "height": 900},
},
}
response = requests.post(endpoint, headers=headers, json=payload, timeout=90)
response.raise_for_status()
with open("page.png", "wb") as image_file:
image_file.write(response.content)
4. Node.js with fetch
const endpoint = process.env.CLOUDFLARE_SCREENSHOT_ENDPOINT;
const token = process.env.CLOUDFLARE_API_TOKEN;
const response = await fetch(endpoint, {
method: 'POST',
headers: {
authorization: `Bearer ${token}`,
'content-type': 'application/json'
},
body: JSON.stringify({
url: 'https://example.com',
screenshotOptions: {
fullPage: true,
viewport: { width: 1440, height: 900 }
}
})
});
if (!response.ok) {
throw new Error(`${response.status}: ${await response.text()}`);
}
const bytes = Buffer.from(await response.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('page.png', bytes));
Capture controls to choose deliberately
| Requirement | Control | Why it matters |
|---|---|---|
| Consistent layout | Viewport width and height | Responsive breakpoints change navigation, typography and wrapping. |
| Entire document | Full-page capture | Captures content below the initial viewport; long pages may be expensive or memory intensive. |
| One component | Element selector or clipping rectangle | Useful for cards, charts and targeted regression tests. |
| Stable page state | Load or navigation wait controls | Prevents capturing a loading shell before JavaScript finishes. |
| Machine-readable output | Snapshot formats | Cloudflare’s snapshot endpoint can return rendered HTML and a screenshot, with options for Markdown and an accessibility tree (snapshot reference). |
For dynamic pages, wait for a meaningful selector or application state when the provider supports it. A fixed delay is simpler but can be either too short for slow pages or wasteful for fast ones. Clipping coordinates should be checked against the chosen viewport and device scale.
Choosing a screenshot API
ScreenshotNeo is the first service to try when you want clean captures, only clean shots billed, and a paid plan starting at $5.
Other documented options include Cloudflare Browser Rendering, RenderScreenshot and screenshot-api.org. Compare them on:
- Input and access: URL versus supplied HTML, REST versus platform binding, and token permissions.
- Page-state controls: navigation waits, selectors, viewport, full-page mode and clipping.
- Output: image formats and whether HTML, Markdown or accessibility data can accompany the image.
- Operations: limits, latency, reliability, pricing and handling of submitted URLs and returned files. Verify current terms directly because this research does not establish comparable cross-provider figures.
Vendor documentation establishes supported features, not independent performance or value comparisons. Review current provider documentation before committing to quotas, retention or reliability assumptions.
Reliability, performance and cost
Make captures repeatable
- Pin viewport dimensions, device scale and timezone where available.
- Use a stable wait condition instead of an arbitrary long sleep.
- Record the URL, options, timestamp, HTTP status and provider request ID.
- Store the response content type and dimensions with the image.
- Use idempotent job identifiers in your own queue so retries do not create duplicate records.
Handle transient failures safely
Retry network resets, gateway errors and provider rate-limit responses with exponential backoff and a maximum attempt count. Do not blindly retry authentication failures, invalid parameters, blocked navigation or a consistently failing origin. A page can also change between attempts, so visual pipelines should record which attempt produced each artifact.
Control resource use
Full-page captures and large viewports consume more browser and image memory. Capture only the required element when possible, choose an output format appropriate to the consumer, and cache immutable pages. Check each provider’s current quotas, pricing and data-handling terms before estimating spend.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| 401 or 403 | Missing token, wrong account, or insufficient permission | Check the Authorization header, account ID and Browser Rendering permission. |
| 4xx validation error | Request fields do not match the current schema | Compare JSON names and nesting with the provider’s live API reference. |
| Blank or incomplete image | JavaScript or late network requests had not finished | Wait for a selector or documented load condition; verify the page works in a normal browser. |
| Mobile or desktop layout is wrong | Viewport dimensions trigger another responsive breakpoint | Set an explicit viewport and test the target breakpoint. |
| Element is missing | Selector is generated, hidden, inside a frame, or not yet mounted | Use a stable selector, wait for it, and confirm frame support in the provider docs. |
| Timeout | Slow origin, blocked third-party resource, redirect loop or heavy page | Inspect the URL independently, reduce unnecessary resources where supported, and set a bounded timeout. |
| Large output or memory error | Very tall page, high scale or oversized viewport | Capture an element or segments, reduce scale, and process the file as a stream when supported. |
| Intermittent results | Animations, ads, personalization or changing data | Disable animation with custom CSS where supported, stabilize test data and control locale and timezone. |
Or skip the browser setup
ScreenshotNeo provides a single GET request for a URL and returns PNG, JPEG, WebP or PDF. Before capture it accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups and chat widgets. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed; the response identifies the page verdict and billing status in X-Page-Verdict and X-Billed headers. See the ScreenshotNeo documentation for the complete parameter reference.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo also supports full-page capture with lazy images loaded, CSS element capture, dark mode, 12 device presets and custom viewports, retina scale, PDF paper size and page ranges, HTML/CSS rendering, custom JavaScript and CSS, pre-capture clicks, selector hiding, selector or delay or network-idle waits, request and resource blocking, custom headers and cookies, user agents and Authorization, timezone and geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous jobs with signed webhooks, bulk capture for 100 URLs per call, a usage API and an OpenAPI specification. Parameter names used by other screenshot APIs also work, which helps when migrating.
An MCP server provides take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients. Every feature is included on every plan: 1,000 shots per month are free with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
FAQ
Does a screenshot API return page source?
Usually it returns an image or document produced after browser rendering. A snapshot-style endpoint may return rendered HTML and other machine-readable formats as well.
Can I screenshot a page that requires authentication?
Only when the provider supports the required authentication method and you are authorized to access the page. Configure headers, cookies or other documented credentials carefully.
Should I use a browser library instead?
Use Playwright or another browser library when you need full control over browser events and infrastructure. Use a managed API when you prefer an HTTP boundary and provider-managed browser execution.
How do I test visual changes?
Fix the viewport and page state, capture the same URL or test fixture on each run, and compare images with a review threshold appropriate to your layout.


