How to Save Browserless Screenshots as PNG, JPEG, or WebP
Set the screenshot format in Browserless, save the returned bytes correctly, and choose PNG, JPEG, or WebP for your capture.
To save a Browserless screenshot as PNG, JPEG, or WebP, set options.type in a POST request to the current REST /screenshot endpoint. Save the raw response bytes directly to a file whose extension matches that format. For example, set "type": "webp" and write the response to screenshot.webp. The current REST endpoint returns the corresponding image content type, such as image/webp. Browserless REST screenshot documentation
Save a screenshot with the Browserless REST API
Get a Browserless API token, then send JSON to your deployment’s /screenshot endpoint. The shared-cloud examples below use the documented production-sfo host; use the host for your own deployment if it differs.
Choose png, jpeg, or webp as the value of options.type. The default example below captures the full page; change fullPage to false or omit it for a viewport capture. See the REST endpoint options.
cURL
curl --fail --show-error --silent \
-X POST \
"https://production-sfo.browserless.io/screenshot?token=YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-H "Cache-Control: no-cache" \
--data '{
"url": "https://example.com/",
"options": {
"fullPage": true,
"type": "webp",
"quality": 80
}
}' \
--output screenshot.webp
Replace webp with png or jpeg, and use the matching file extension. The quality setting is relevant to lossy formats such as JPEG and WebP; it does not apply to PNG. Browserless documents WebP quality 80 in an example, but that is an example value, not a universal setting. Omit quality if you want the browser’s default for the selected lossy format.
Python
import requests
TOKEN = "YOUR_API_TOKEN"
IMAGE_TYPE = "webp" # png, jpeg, or webp
OUTPUT = f"screenshot.{IMAGE_TYPE}"
endpoint = "https://production-sfo.browserless.io/screenshot"
response = requests.post(
endpoint,
params={"token": TOKEN},
headers={"Cache-Control": "no-cache"},
json={
"url": "https://example.com/",
"options": {
"fullPage": True,
"type": IMAGE_TYPE,
"quality": 80,
},
},
timeout=90,
)
response.raise_for_status()
with open(OUTPUT, "wb") as image_file:
image_file.write(response.content)
print(f"Saved {OUTPUT} ({response.headers.get('Content-Type', 'unknown content type')})")
Use binary mode, "wb", so Python writes the image bytes unchanged. Remove quality when IMAGE_TYPE is png.
Node.js
import { writeFile } from "node:fs/promises";
const token = process.env.BROWSERLESS_TOKEN;
if (!token) throw new Error("Set BROWSERLESS_TOKEN before running this script");
const type = "webp"; // png, jpeg, or webp
const response = await fetch(
`https://production-sfo.browserless.io/screenshot?token=${encodeURIComponent(token)}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
"Cache-Control": "no-cache",
},
body: JSON.stringify({
url: "https://example.com/",
options: { fullPage: true, type, quality: 80 },
}),
},
);
if (!response.ok) {
throw new Error(`Browserless returned HTTP ${response.status}: ${await response.text()}`);
}
const bytes = Buffer.from(await response.arrayBuffer());
const filename = `screenshot.${type}`;
await writeFile(filename, bytes);
console.log(`Saved ${filename} (${response.headers.get("content-type")})`);
This is an ES module script. Set the token in the environment, for example with BROWSERLESS_TOKEN=your-token node screenshot.mjs. Don’t commit the token or print it to logs. The REST quickstart uses the same binary response handling: read an array buffer in Node.js, and write response content in binary mode in Python. Browserless REST quickstart
What happens if the response is an error?
Do not blindly save every response as an image. An HTTP error body may be JSON or HTML, resulting in a file named .png that is not actually an image. Use curl --fail, Python’s raise_for_status(), or check response.ok in Node.js before writing. For debugging, inspect the HTTP status and response content type.
Choose PNG, JPEG, or WebP
| Format | Choose it when | Notes |
|---|---|---|
| PNG | You need lossless output or transparency. | PNG is lossless; the quality option does not apply. For transparency, set omitBackground: true where supported and preserve the PNG output. |
| JPEG | Your downstream workflow calls for JPEG. | JPEG is a lossy format. You can use the screenshot quality option; the supplied Browserless docs do not establish a universal quality value or file-size comparison. |
| WebP | Your downstream workflow supports WebP. | WebP is supported by the current REST API and BrowserQL. Quality can be specified; choose a value based on your own output requirements. |
There is no format that is always best. Pick based on the needs of the system that will consume the file: compatibility, transparency, and any quality/compression requirements. The cited Browserless documentation establishes PNG as lossless and documents quality handling, but it does not provide a comparative benchmark for visual quality or file size. The legacy BaaS v1 docs that say WebP is unavailable are marked deprecated; use the current REST or BrowserQL documentation instead. Current REST docs · BrowserQL screenshot schema · Deprecated BaaS v1 page
Capture more than the visible viewport
The screenshot’s dimensions and content depend on how you capture the page. Browserless documents Puppeteer-style screenshot options for the REST API. Common choices include:
fullPage: truecaptures the full page instead of only the current viewport.selectorcaptures a particular element by CSS selector. In the REST request, the selector is at the top level alongsideurl, not insideoptions.clipcaptures a fixed region using coordinates and dimensions.omitBackgroundomits the default white background to allow transparency; choose an output workflow that retains transparency, such as PNG.qualityapplies to supported lossy formats; it is ignored for PNG.scrollPage: truescrolls through a page before capture to trigger lazy-loaded content. Combine it withfullPage: truewhen you need the whole long page.
For example, add "selector": "main article" at the top request level to capture a matching element instead of the full page. For a fixed region, put "clip": {"x": 0, "y": 0, "width": 800, "height": 600} inside options. Ensure the selector exists and the clip coordinates match the rendered viewport. REST configuration and screenshot options
Save BrowserQL screenshots
BrowserQL’s screenshot mutation accepts a format and returns the image as base64 when you request its base64 field. Unlike the REST endpoint’s raw image response, this result must be decoded before writing it to an image file. BrowserQL screenshots guide
mutation SaveWebP {
goto(url: "https://example.com") {
status
}
screenshot(type: webp, quality: 80, fullPage: true) {
base64
}
}
Send that GraphQL mutation as a JSON POST to the BrowserQL endpoint with your token. Here is a cURL request that stores the JSON response for decoding:
curl --fail --show-error \
"https://production-sfo.browserless.io/chromium/bql?token=YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{"query":"mutation SaveWebP { goto(url: \"https://example.com\") { status } screenshot(type: webp, quality: 80, fullPage: true) { base64 } }","variables":{},"operationName":"SaveWebP"}' \
--output response.json
Decode the data.screenshot.base64 value from the JSON response, not the entire response body. In Node.js, parse the JSON and call Buffer.from(base64, "base64"); in Python, use base64.b64decode(base64_string). Check that the response contains data.screenshot.base64 before decoding because GraphQL errors may appear in an otherwise successful HTTP response.
BrowserQL also supports waitForImages, selector, clip, fullPage, and omitBackground. Its schema documents a screenshot timeout. For a transparent result, use omitBackground: true and PNG. Screenshot mutation options
Wait for the right content
A screenshot captures the browser state at the time the screenshot operation runs. If the page is still rendering, images may be absent or content may be incomplete. Browserless documents shared request wait options, navigation configuration, and screenshot-specific ways to wait for images or a selector.
- For images, use the documented wait-for-images option where available.
- For a particular component, wait for its selector instead of relying on an arbitrary delay.
- For lazy-loaded images below the fold, enable page scrolling before taking a full-page screenshot so the page can trigger those loads.
- For slow navigation, review Browserless navigation and timeout settings, then set a timeout that fits the page and your request budget.
Waiting longer can improve completeness but increases latency. A wait-for-all-images step can also take longer on pages with slow or broken image resources; if only a specific region matters, wait for the relevant selector instead. REST wait and navigation options · BrowserQL waitForImages option
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| The image file cannot be opened. | An HTTP error response or JSON error body was written with an image extension. | Check the HTTP status before writing. Use curl --fail, raise_for_status(), or a Node.js response.ok check. Inspect the content type. |
| The filename says WebP, but downstream software rejects it. | The requested type and extension may not match, or the consumer may not support that format. | Set options.type to the intended format and use its matching extension. Confirm the receiving system supports it; choose PNG or JPEG if required. |
| Quality has no effect. | The selected format is PNG. | PNG is lossless and ignores quality. Select JPEG or WebP if you need the quality option. |
| The screenshot is blank or shows a CAPTCHA, access denied page, or 403 content. | The target site may be blocking automation or returning an access challenge. | Check the actual captured page and HTTP/navigation status. Browserless documents its separate /unblock API for bot-detection cases; that is a different endpoint and workflow from ordinary /screenshot. |
| Images or below-the-fold sections are missing. | The capture happened before resources loaded, or lazy-loaded content was never triggered. | Wait for images or a relevant selector. For a long page, trigger lazy loading by scrolling, then capture with full-page mode. |
| A selector capture returns the wrong area or fails. | The selector is missing, not yet rendered, or placed inside the wrong part of the request. | Confirm it matches an element in the rendered page, wait for it, and put REST selector at the top request level. Use clip for fixed coordinates instead. |
| BrowserQL returns JSON but no image file. | The result is base64 data nested in the GraphQL response; it is not a raw image response. | Check for GraphQL errors, extract data.screenshot.base64, decode it, then write the resulting bytes. |
| The request times out. | Navigation, page rendering, or resource loading exceeded the configured timeout. | Use a suitable timeout and wait for a specific condition rather than an unnecessarily long fixed delay. Check whether a slow or unavailable resource is holding up capture. |
Performance, reliability, and cost considerations
Full-page images can contain substantially more page content than viewport captures, and waiting for images or scrolling to trigger lazy loads adds work. Use viewport captures when that is all you need, and target a selector or clip when only one region is required. The Browserless material supplied here does not specify a performance benchmark, pricing, or retry guarantees, so measure latency and usage for your own pages and account.
Handle failures explicitly and avoid treating every retry as harmless: a retry repeats a browser request and can add latency or usage. For automated jobs, record status, content type, target URL, and capture settings without logging the API token. Use bounded timeouts and retry only transient failures according to your application’s needs. For format-dependent processing, validate the resulting file or its content type before handing it to downstream code.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server for developers. One GET request returns a PNG, JPEG, WebP, or PDF; its [API documentation](https://screenshotneo.com/docs/) lists the request options and examples. For a WebP shot:
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://stripe.com \
-o shot.webp
Cookie banners are accepted like a visitor would accept them, and 60+ known consent platforms, newsletter popups, and chat widgets are removed before the shot; each step can be turned off. Bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and each response reports the page verdict and billing status in headers. An MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.
Sign up free for 1,000 screenshots a month, with no card required.
FAQ
Does the output filename control the image format?
No. Set the format in the request and make the filename extension match it. An extension alone does not convert the response bytes.
Can I save WebP from current Browserless?
Yes. Current Browserless REST and BrowserQL documentation list WebP. The contrary limitation appears on a deprecated BaaS v1 page; follow the current endpoint docs.
Can I capture HTML that I provide instead of navigating to a URL?
The REST endpoint supports an html field for inline HTML. Use either html or url in that request, not both. BrowserQL also documents setting page content before the screenshot mutation. REST inline HTML example
Can I make a transparent screenshot?
Browserless documents omitBackground to hide the default white background. Use PNG when the workflow needs transparency; JPEG does not retain transparency. BrowserQL screenshot options


