Browserless Screenshot API: Complete REST Guide
Learn how to capture URL, HTML, full-page, clipped, and element screenshots with the Browserless REST API.
The Browserless Screenshot API takes a URL or supplied HTML, renders it in a hosted browser, and returns image bytes. Send an authenticated POST request to the current /screenshot REST endpoint with a JSON body, then save the binary response as PNG, JPEG, or WebP.
This guide covers URL and HTML input, viewport and full-page captures, element and region screenshots, waits, lazy-loaded content, resource blocking, error handling, and production design. The current documentation is the Browserless Screenshot API guide; the older BaaS v1 screenshot page is deprecated.
How do I take a screenshot with the Browserless REST API?
- Create a Browserless account and obtain an API token.
- Set the current REST screenshot endpoint for your Browserless region or deployment in an environment variable.
- POST JSON containing either
urlorhtml, plus optional screenshot settings underoptions. - Read the response as binary data and write it to a file or object store.
Do not send url and html together in the documented HTML mode. Use one input per request.
Minimal cURL request
export BROWSERLESS_ENDPOINT='https://YOUR_BROWSERLESS_HOST/screenshot'
export BROWSERLESS_TOKEN='YOUR_TOKEN'
curl -sS -X POST "$BROWSERLESS_ENDPOINT?token=$BROWSERLESS_TOKEN" \\
-H 'Content-Type: application/json' \\
--data '{"url":"https://example.com"}' \\
-o screenshot.png
The response body is the image itself. Keep the response binary; do not parse it as JSON.
Python
import os
import requests
endpoint = os.environ['BROWSERLESS_ENDPOINT']
token = os.environ['BROWSERLESS_TOKEN']
response = requests.post(
endpoint,
params={'token': token},
json={'url': 'https://example.com'},
timeout=90,
)
response.raise_for_status()
with open('screenshot.png', 'wb') as image_file:
image_file.write(response.content)
Node.js
const endpoint = process.env.BROWSERLESS_ENDPOINT;
const token = process.env.BROWSERLESS_TOKEN;
const response = await fetch(`${endpoint}?token=${encodeURIComponent(token)}`, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ url: 'https://example.com' })
});
if (!response.ok) {
throw new Error(`Browserless returned ${response.status}: ${await response.text()}`);
}
const image = Buffer.from(await response.arrayBuffer());
await require('node:fs').promises.writeFile('screenshot.png', image);
Request structure
The request is a JSON object. Supply exactly one rendering source:
| Field | Purpose |
|---|---|
url |
Navigate the hosted browser to a page. |
html |
Render supplied HTML instead of navigating to a URL. |
options |
Screenshot, viewport, wait, navigation, and resource controls. |
selector |
Capture one matching element. The guide places this at the top level, not inside options. |
Capture supplied HTML
curl -sS -X POST "$BROWSERLESS_ENDPOINT?token=$BROWSERLESS_TOKEN" \\
-H 'Content-Type: application/json' \\
--data '{
"html": "<!doctype html><html><body><h1>Invoice</h1></body></html>",
"options": {"fullPage": true}
}' \\
-o html-capture.png
When using html, omit url. Inline HTML is useful for invoices, reports, email previews, and deterministic templates.
Screenshot options
The current REST documentation lists controls for the following capture dimensions.
| Need | Use |
|---|---|
| Viewport only | Default screenshot behavior. |
| Entire page | Enable the full-page option. |
| One element | Put a CSS selector at the request top level. |
| Fixed rectangle | Set options.clip with the documented rectangle coordinates. |
| Specific output | Select PNG, JPEG, or WebP in the format option. |
| Smaller JPEG/WebP files | Set image quality where supported by the selected format. |
| Different browser size | Set the viewport width and height. |
| Retina-style output | Set the device scale factor. |
Full-page capture
{
"url": "https://example.com/article",
"options": {
"fullPage": true
}
}
Full-page capture measures the rendered document, so content loaded only after scrolling can be absent. Scroll or otherwise trigger lazy loading before the screenshot when the page depends on it.
Element capture
{
"url": "https://example.com/dashboard",
"selector": "main .sales-chart"
}
The selector must match the element you intend to capture. A missing or late-rendering element is a common cause of an empty or failed result; add a selector wait before capturing.
Clip a region
{
"url": "https://example.com/map",
"options": {
"clip": {
"x": 0,
"y": 120,
"width": 900,
"height": 500
}
}
}
Use clipping when a fixed rectangle is more stable than a CSS selector. Coordinates are relative to the rendered page.
Waiting for dynamic pages
Modern pages often finish navigation before their useful content appears. Browserless documents waits based on events, functions, selectors, or timeouts, as well as navigation settings through gotoOptions. Choose the narrowest condition that represents readiness.
- Selector wait: wait until a chart, table, or content container exists.
- Event wait: wait for the page event required by your application.
- Function wait: wait for an application-specific readiness condition.
- Timeout wait: use a bounded delay when no reliable signal exists.
- Navigation settings: configure navigation behavior through
gotoOptions.
Prefer a selector or application readiness signal over a large fixed delay. Keep every wait bounded so a broken page cannot consume a worker indefinitely.
Blocking resources and reducing work
The API supports rejecting selected resource types or request patterns. Blocking advertising, analytics, video, or other nonvisual resources can reduce page work, but blocking a stylesheet, font, script, or API request that the page needs will change the screenshot or leave it incomplete.
{
"url": "https://example.com",
"options": {
"rejectResourceTypes": ["image"]
}
}
Use resource blocking only after identifying which requests are safe to reject for the page you capture. Validate the resulting image whenever you change the block list.
Authentication, headers, and private pages
For authenticated pages, pass the headers, cookies, or other navigation settings supported by the current API documentation. Keep tokens and session cookies in server-side secret storage. Never place a Browserless token in browser JavaScript shipped to visitors.
For sensitive captures, use a dedicated account with the minimum permissions needed, avoid writing response data to shared temporary directories, and delete images that do not need retention.
Handling responses safely
- Check the HTTP status before writing the file.
- Read the body as bytes, not text.
- Use the response content type and requested format to choose a file extension.
- Store the image atomically, then publish its final location.
- Log request identifiers and timing without logging tokens or private page contents.
Retries should be bounded and used for transient transport or service failures. Retrying a deterministic page error without changing the URL, wait condition, or authentication will usually produce the same result.
Common errors and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| 401 or authentication error | Missing, invalid, or incorrectly encoded token. | Send the token in the documented token query parameter and rotate an exposed token. |
| 400 or validation error | Malformed JSON, unsupported option, or both url and html supplied. |
Validate JSON, remove unknown fields, and send exactly one input mode. |
| Blank image | The site blocks automation, the page failed to load, or capture happened before rendering. | Inspect the target manually, add an appropriate wait, and check the documented /unblock workflow for some bot-detection cases. It does not solve every protected site. |
| CAPTCHA or access denied | Automation defenses detected the hosted browser. | Do not treat the result as page content. Review site access requirements and the separate Browserless unblock API. |
| Missing chart or element | Selector is wrong or asynchronous content was not ready. | Confirm the selector, wait for it, and ensure required API requests were not blocked. |
| Lazy images missing | Images load only after scrolling. | Scroll before a full-page capture or use a page readiness function that triggers lazy loading. |
| Truncated page | Viewport capture was used or the document had not finished expanding. | Enable full-page capture and wait for the final content height. |
| Corrupt downloaded file | Binary response was decoded as text or an error body was saved as an image. | Check status first and write raw bytes. |
Performance, reliability, and cost planning
- Performance: page JavaScript, fonts, images, third-party requests, waits, and full-page dimensions all affect completion time. Block only resources that are not needed.
- Reliability: use bounded waits, status checks, idempotent output names, and limited retries. Record whether failures occurred during navigation, waiting, or image writing.
- Consistency: set a fixed viewport, device scale factor, format, and wait condition when comparing screenshots over time.
- Cost: the research sources reviewed for this guide do not establish current Browserless prices, quotas, rate limits, or concurrency limits. Check your account and current pricing documentation before sizing a production workload.
Browserless REST API versus the deprecated BaaS v1 page
Use the current REST screenshot documentation for new integrations. Browserless marks its legacy BaaS v1 screenshot page as deprecated and points readers to newer BaaS v2 or BrowserQL documentation. Examples copied from v1 should not be treated as current behavior.
Or skip the browser setup
ScreenshotNeo provides a one-call website screenshot API when you do not want to operate browser automation yourself. It accepts 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; each cleanup step can be disabled.
Only clean shots are billed. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and whether the request was billed. ScreenshotNeo also provides an MCP server with take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.
cURL
curl -G 'https://api.screenshotneo.com/v1/shot' \\
-d access_key=YOUR_API_KEY \\
--data-urlencode url=https://example.com \\
-o shot.webp
Python
import requests
r = requests.get(
'https://api.screenshotneo.com/v1/shot',
params={'access_key': 'YOUR_API_KEY', 'url': 'https://example.com'},
timeout=90,
)
r.raise_for_status()
open('shot.webp', 'wb').write(r.content)
Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`ScreenshotNeo returned ${res.status}`);
require('node:fs').promises.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
See the ScreenshotNeo API documentation for the complete option list, including full-page and element capture, dark mode, device presets, custom CSS and JavaScript, clicks, waits, request blocking, headers, cookies, geolocation, transparent backgrounds, resizing, caching, signed links, asynchronous jobs, bulk capture, usage, and the OpenAPI specification.
There are 1,000 free screenshots each month with no card. Paid plans start at $5 for 3,000 screenshots, and every feature is included on every plan. Create a free ScreenshotNeo account.
FAQ
Can I capture a full-page screenshot?
Yes. Enable the full-page option and account for lazy-loaded content by scrolling or waiting for it to load.
Can I capture only one element?
Yes. Provide the CSS selector at the top level of the request body, as shown in the current guide.
Can I send HTML instead of a URL?
Yes. Send the html field and omit url.
What should I do when a site returns a CAPTCHA?
Treat it as an automation defense rather than a valid screenshot. Browserless documents a separate /unblock route for some cases, but no route is guaranteed to bypass every protected site.
Which Browserless screenshot documentation is current?
Use the current REST screenshot guide. The BaaS v1 screenshot page is explicitly deprecated.


