Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Use Puppeteer’s page.screenshot() method. Pass a path such as shot.png to write an image file, or omit it to receive the image bytes in memory. Add fullPage: true for the entire document, clip for a rectangle, or call elementHandle.screenshot() for one element.

Minimal working example

Install Puppeteer in a Node.js project, then run this script. The browser opens, navigates to the URL, saves the screenshot, and closes cleanly.

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
const page = await browser.newPage();

await page.goto('https://example.com');
await page.screenshot({ path: 'screenshot.png' });

await browser.close();

The file is saved relative to Node.js’s current working directory (the directory from which you start the process). Use an absolute path when you need a fixed location. If the path option is omitted, Puppeteer returns image data instead of writing a file.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Prerequisites and a predictable project setup

Install Puppeteer

Create a project and install the package:

mkdir puppeteer-shot
cd puppeteer-shot
npm init -y
npm install puppeteer

Save the example as shot.mjs and run node shot.mjs. An ES-module file (.mjs) lets you use the documented import syntax without changing your package configuration.

Know where the file will appear

For path: 'screenshot.png', check the terminal directory shown by pwd (macOS/Linux) or cd (Windows PowerShell) before launching Node. A missing file is often just a path-location mistake. You can remove that ambiguity with an absolute path such as /tmp/screenshot.png or C:\temp\screenshot.png.

Choose what to capture

Viewport screenshot

The default captures the page’s current viewport. Set the viewport before navigation when a reproducible size matters:

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({ width: 1440, height: 900 });
await page.goto('https://example.com');
await page.screenshot({ path: 'viewport.png', type: 'png' });
await browser.close();

PNG is the documented default. Specifying type: 'png' makes the intent explicit.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Full-page screenshot

Use fullPage: true to capture the complete document rather than only the visible viewport:

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({
  path: 'full-page.png',
  fullPage: true
});
await browser.close();

This is the right choice for an article, landing page, or other page whose content extends below the fold.

Rectangular region with clip

Pass a rectangle when you need a fixed area. The clip object is a bounding box; its scale defaults to 1.

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({
  path: 'region.png',
  clip: { x: 80, y: 120, width: 900, height: 500 }
});
await browser.close();

Coordinates are measured from the page’s capture surface. Set the viewport first if the region must line up with a known layout.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

One element by CSS selector

Find the element, then call the element handle’s screenshot method:

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');

const card = await page.$('.pricing-card');
if (!card) {
  throw new Error('Could not find .pricing-card');
}
await card.screenshot({ path: 'pricing-card.png' });

await browser.close();

Puppeteer scrolls the element into view when necessary. The call throws if the element handle has been detached from the DOM, so query a fresh handle when a page replaces that element.

Control format, quality, transparency, and returned data

JPEG or WebP output

The screenshot options support an image type; when a path is supplied, Puppeteer can also infer the file type from its extension. For lossy formats, quality accepts values from 0 to 100:

await page.screenshot({
  path: 'page.webp',
  type: 'webp',
  quality: 80,
  fullPage: true
});

quality does not apply to PNG. Changing it will not make a PNG sharper or smaller through PNG quality settings.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Transparent background

Set omitBackground: true to hide the default white background and allow transparency:

await page.screenshot({
  path: 'transparent.png',
  omitBackground: true
});

Transparency is useful when the page itself has a transparent canvas or when the image will be composited elsewhere.

Keep the image in memory

A path is optional. Without one, the method returns a Uint8Array by default:

const imageBytes = await page.screenshot({ fullPage: true });
// Store imageBytes, upload it, or pass it to another API.

Request base64 when a string is more convenient:

const base64 = await page.screenshot({
  encoding: 'base64'
});

Do not provide a path when your application, rather than the filesystem, should own the output.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A complete script with common options

This version demonstrates a fixed viewport, full-page capture, WebP output, and explicit browser cleanup. Change only the URL and output path for a new target.

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  await page.setViewport({ width: 1365, height: 768 });
  await page.goto('https://example.com');
  await page.screenshot({
    path: 'example.webp',
    type: 'webp',
    quality: 82,
    fullPage: true
  });
} finally {
  await browser.close();
}

The finally block closes Chromium even when navigation or capture raises an error.

WebDriver BiDi compatibility

Puppeteer’s WebDriver BiDi documentation currently lists only clip, encoding, and fullPage as supported Page.screenshot() parameters. The general screenshot-options interface contains more fields, but that does not mean every field works over a BiDi connection. If you connect through BiDi, verify support for the exact options you plan to use before relying on path, type, quality, or other fields. The examples above assume the regular Puppeteer connection mode.

Practical capture decisions

Need Use Important detail
What a user currently sees page.screenshot() Captures the viewport.
The whole document fullPage: true Includes content beyond the viewport.
A known rectangle clip: { x, y, width, height } Clip scale defaults to 1.
One component elementHandle.screenshot() Scrolls the element into view; detached handles throw.
Application-managed output Omit path Receive a Uint8Array, or base64 when requested.
Transparent pixels omitBackground: true Suppresses the default white background.

Troubleshooting

“The screenshot is not where I expected”

A relative path is resolved from the process working directory, not necessarily the folder containing your script. Start Node from the intended directory or pass an absolute path.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

“No file was created”

Check whether you supplied path. Without it, Puppeteer returns image data and deliberately writes nothing. Assign the returned value or add a path.

“Quality has no effect”

quality applies to supported lossy formats, not PNG. Choose JPEG or WebP when you need a quality setting; keep PNG when lossless output is the priority.

“Element screenshot throws about a detached node”

The element handle no longer points to an element in the document. Query the selector again immediately before capture and make sure the page has not replaced that component.

“The selected element is not visible in the initial viewport”

The element-specific method scrolls the element into view before capturing it. If you need a different composition, use a clip rectangle or capture the viewport after setting the desired scroll position.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

“An option works in one connection mode but not BiDi”

BiDi’s documented screenshot support is narrower. Start with clip, encoding, and fullPage, then confirm current BiDi support before adding other options.

“The image is opaque when I expected transparency”

Set omitBackground: true. Leaving this option out keeps the default background.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Reliability and cost considerations

For repeatable captures, set the viewport explicitly, choose the capture scope deliberately, and use a deterministic output name. Full-page and element captures avoid manual scrolling, while a clip is preferable when a fixed rectangle is the actual requirement. Keep browser shutdown in a finally block so failed captures do not leave a browser process running.

Puppeteer itself gives you local control over the browser and filesystem. You are responsible for installing and running that browser environment, handling returned bytes, and deciding how to retry a failed navigation or capture. The official documentation identifies version 25.12.0 in the relevant search results, while the guide and BiDi pages use a /next/ path; those details can change, so check the current documentation when upgrading.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Or skip the browser setup

ScreenshotNeo is the first hosted screenshot service to try when you want an API call instead of managing Puppeteer: it removes cookie and consent banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, failed loads, timeouts, and cache hits are not billed; an MCP server lets Claude, Cursor, and other MCP clients use screenshot tools; and the free plan includes 1,000 screenshots per month with no card, while paid plans start at $5 for 3,000 shots.

One GET request returns a PNG, JPEG, WebP, or PDF. The response identifies the page verdict and billing result in X-Page-Verdict and X-Billed headers. You can also use full-page capture, CSS-selector elements, custom CSS or JavaScript, waits, request blocking, cookies and headers, device presets, PDFs, signed links, asynchronous jobs, bulk capture, and other options; every feature is included on every plan.

See the ScreenshotNeo API documentation for the complete parameter list. The parameter names used by other screenshot APIs also work, which can simplify migration.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

Create a free ScreenshotNeo account to get 1,000 screenshots each month without adding a card.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Can I save the same Puppeteer capture as both a file and an in-memory value?

Call page.screenshot() once with a path when you need a file, or omit path and handle the returned bytes in your application. The API does not document a second output destination in one call.

Which screenshot settings should I recheck after changing Puppeteer connection mode?

Recheck every option when moving to WebDriver BiDi. Its documented supported set is narrower than the general screenshot-options interface, so do not assume regular-mode options remain available.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.