How to Save Puppeteer Screenshots as PNG, JPEG, or WebP
Save Puppeteer screenshots as PNG, JPEG, or WebP with the right extension, format, and quality options. Includes file, memory, and element capture examples.
Use Puppeteer’s page.screenshot() and set a file path with the extension you want: .png, .jpg or .jpeg, or .webp. Puppeteer documents PNG as the default; you can also set type explicitly. For JPEG and WebP, quality accepts a number from 0 to 100. It does not apply to PNG.
This runnable example saves all three formats:
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({ path: 'capture.png', type: 'png' });
await page.screenshot({ path: 'capture.jpg', type: 'jpeg', quality: 85 });
await page.screenshot({ path: 'capture.webp', type: 'webp', quality: 85 });
} finally {
await browser.close();
}
Install Puppeteer in your project with npm install puppeteer, save the example as an .mjs file, and run it with Node.js. Change the target URL to the page you need. The quality value of 85 is an example, not a universal recommendation; check the resulting image for your use case.
1. Choose a format and matching extension
| Format | Path example | Explicit type | Quality |
|---|---|---|---|
| PNG | page.png |
'png' |
Not applicable |
| JPEG | page.jpg or page.jpeg |
'jpeg' |
0–100 |
| WebP | page.webp |
'webp' |
0–100 |
A path extension can determine the output format. Setting type makes your intention explicit. When you set both, keep the type and extension aligned so that the filename matches the file contents.
- Choose PNG when the downstream workflow expects PNG. PNG is the documented default, and the quality option does not apply to it.
- Choose JPEG when the downstream workflow expects JPEG. Set
qualityif you want to control the format’s quality setting. - Choose WebP when the downstream workflow expects WebP. Set
qualityif needed.
The Puppeteer documentation describes the supported formats and options; it does not prescribe one universally best quality value or provide comparative file-size benchmarks. Pick the output your consumer requires, then inspect it for the page and purpose.
2. Save directly to a file
Provide path to save the screenshot. A relative path is resolved from the process’s current working directory, so capture.png is written relative to the directory from which you run Node.js. Ensure the destination directory exists and is writable.
await page.screenshot({ path: 'page.png' });
await page.screenshot({ path: 'page.jpeg', type: 'jpeg', quality: 85 });
await page.screenshot({ path: 'page.webp', type: 'webp', quality: 85 });
These calls are asynchronous. Await each one before closing the browser or using the output. If you omit path, Puppeteer returns image data in memory instead of saving a file.
3. Use the screenshot in memory
Without a path, page.screenshot() returns a Uint8Array by default. You can pass those bytes to code that uploads or processes binary data. With encoding: 'base64', the result is a base64 string instead.
const bytes = await page.screenshot({ type: 'png' });
console.log(bytes instanceof Uint8Array); // true
const base64 = await page.screenshot({ type: 'jpeg', quality: 85, encoding: 'base64' });
console.log(typeof base64); // 'string'
If you need a file but want to handle writing yourself, write the returned bytes with Node’s filesystem API:
import { writeFile } from 'node:fs/promises';
const bytes = await page.screenshot({ type: 'webp', quality: 85 });
await writeFile('page.webp', bytes);
Use the byte result for binary workflows and base64 only when the receiving interface expects a base64 string. Remember to await the screenshot before processing the result.
4. Capture one element instead of the whole page
Use an element handle’s screenshot() method to capture a specific element. Puppeteer scrolls the element into view when needed. The handle must still refer to an element attached to the DOM; if the page replaces or removes it before capture, the call throws.
const card = await page.$('.product-card');
if (!card) {
throw new Error('Could not find .product-card');
}
await card.screenshot({ path: 'product-card.webp', type: 'webp', quality: 85 });
If the target is dynamic, locate it after navigation and any page updates that replace its DOM node. For a full page, use page.screenshot(); for one element, use the element handle method.
5. cURL, Python, and Node.js options
Puppeteer is a Node.js library, so it does not expose a Puppeteer API in cURL or Python. The following examples use ScreenshotNeo’s website screenshot API to request PNG, JPEG, or WebP output from those environments. Create an API key and consult the ScreenshotNeo API documentation for request options.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://stripe.com \
-o shot.webp
For PNG or JPEG output, request that format using the API’s documented format parameter and use a matching output filename. Avoid assuming an extension alone changes the response format; check the API docs for the applicable parameter names.
Python
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.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://stripe.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const bytes = new Uint8Array(await res.arrayBuffer());
await import('node:fs/promises').then(({ writeFile }) => writeFile('shot.webp', bytes));
6. Or skip the browser setup
With ScreenshotNeo, one GET request returns a website screenshot as PNG, JPEG, or WebP, or a PDF. The same call works from cURL, Python, or Node.js; see the API documentation for format parameters and the full set of options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
ScreenshotNeo accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server gives AI agents tools for screenshots, page information, and PDF capture. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.
Sign up for 1,000 free screenshots a month, with no card required.
7. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| The file extension does not match the image type | The path and explicit type disagree, or the consumer expects a different format. |
Use a matching pair such as path: 'page.webp', type: 'webp'. If in doubt, inspect the output with the software that consumes it. |
Changing quality has no effect on PNG |
The quality option does not apply to PNG. | Use JPEG or WebP when you need the documented quality setting, or keep PNG and omit quality. |
| No file appears on disk | No path was supplied, the relative path points somewhere unexpected, or the directory is not writable. |
Supply a path, check the process working directory, and confirm the destination exists and can be written. |
| The screenshot result is not ready when used | The asynchronous screenshot call was not awaited. | Use await page.screenshot(...) before processing the bytes or closing the browser. |
| Element screenshot throws | The handle may have been detached because the page replaced or removed the element. | Find the element again immediately before capture and ensure it remains attached. |
| Element selector returns no handle | The selector does not match at lookup time, perhaps because the page has not rendered the element. | Check the selector and wait for the page state that creates the element before querying it. |
8. Performance, reliability, and cost considerations
Screenshot capture is asynchronous, so wait for each capture before using its output. For workflows that write files, use a stable output directory and choose distinct paths when saving multiple formats. For in-memory workflows, avoid converting binary bytes to base64 unless the receiver requires it, since that adds an encoding step.
Puppeteer is a browser automation library, so your code is responsible for launching and closing the browser and handling page navigation and errors. Put browser cleanup in a finally block, as in the main example, so failures during navigation or capture do not skip the close call.
The cited Puppeteer documentation does not provide a universal file-size or capture-speed comparison among PNG, JPEG, and WebP, nor does it establish a best quality number. Choose based on your downstream format requirements, inspect representative output, and measure your own workload if size or latency matters. The Puppeteer examples do not involve a per-screenshot service price; the relevant costs are your own compute and operating costs. A hosted API has its own plan limits and billing rules, which should be checked in that provider’s documentation.
9. Frequently asked questions
Does Puppeteer support WebP screenshots?
Yes. The current Puppeteer image format type includes webp. Use a .webp path or set type: 'webp'.
What is the default screenshot format?
The options reference documents PNG as the default format.
Can I set quality for PNG?
No. The quality option does not apply to PNG. It is documented for non-PNG formats on a 0–100 scale.
Does Puppeteer save a file if I omit path?
No. Without a path, the result is returned in memory as a Uint8Array by default, or as a base64 string when you request encoding: 'base64'.
Can I screenshot a single element?
Yes. Use ElementHandle.screenshot(). The element is scrolled into view if necessary, but capture fails if the handle has been detached from the DOM.


