ScreenshotNeo

BlogComparisons

Compare Puppeteer and Playwright for Full-Page Website Screenshots

Puppeteer and Playwright both capture full-page screenshots with `fullPage: true`. Compare their documented options, runnable examples, setup, and tradeoffs.

By the ScreenshotNeo team4 October 20269 min read

Both Puppeteer and Playwright can capture a full-page website screenshot with the same basic JavaScript call: await page.screenshot({ path: 'screenshot.png', fullPage: true });. Each framework captures beyond the visible viewport to include the scrollable page. For a single capture, neither API has an obvious advantage; choose based on your existing browser automation, the output and controls you need, and how you will make captures reproducible.

The official documentation reviewed does not establish that either framework is faster, more memory-efficient, or more faithful in a general comparison. Those outcomes depend on the page, browser build, host, and capture conditions. Measure your own workload if they matter.

At a glance

Question Puppeteer Playwright
Full-page option fullPage: true; documented default is false fullPage: true
Save directly to a file Yes, with path Yes, with path
Capture image data Screenshot call returns image data when no path is supplied Documented buffer output is available when no path is supplied
Element capture Documented through ElementHandle.screenshot() Documented through locator or element screenshot APIs
Other controls Image type, clipping, quality where applicable, transparent background Image type, clipping, quality, transparent background, masking
Universal performance winner Not established by the official references reviewed; benchmark your pages and environment.

What full-page means

Playwright describes a full-page screenshot as capturing the full scrollable page as if it fit on a very tall screen. Puppeteer likewise defines fullPage as capturing the full page when true. This is distinct from taking a screenshot of only the current viewport, clipping a rectangle, or capturing one element.

Full-page capture does not by itself guarantee that every page element has finished rendering or that content loaded only after scrolling is present. Pages with lazy images, animation, sticky headers, live data, or delayed fonts need an intentional readiness strategy and visual inspection.

Playwright: complete JavaScript example

Install Playwright and its browser, then save this as capture-playwright.mjs. Replace the URL with the page you are allowed to capture.

npm install playwright
npx playwright install chromium
import { chromium } from 'playwright';

const browser = await chromium.launch({ headless: true });
try {
  const page = await browser.newPage({
    viewport: { width: 1440, height: 900 },
    deviceScaleFactor: 1,
  });

  await page.goto('https://example.com', {
    waitUntil: 'networkidle',
    timeout: 60_000,
  });

  await page.screenshot({
    path: 'playwright-full-page.png',
    fullPage: true,
    type: 'png',
  });
} finally {
  await browser.close();
}

Run it with node capture-playwright.mjs. The networkidle condition can be unsuitable for applications that keep network connections open or poll continuously. In that case, use a navigation condition such as domcontentloaded, wait for a page-specific selector, and optionally wait a short, deliberate delay for a known render step. Do not assume network silence alone means the page is visually ready.

Capture to a buffer

Omit path to receive the screenshot as a buffer for upload, hashing, or image processing:

const image = await page.screenshot({ fullPage: true, type: 'png' });
// image is a Buffer in Node.js; pass it to your storage or image-processing code.

Playwright also documents element screenshots and options including clipping, image format, quality, transparent background, and masking. Consult the Playwright screenshots guide and Page screenshot API for version-specific details.

Puppeteer: complete JavaScript example

Install Puppeteer, which downloads a compatible browser as part of its standard installation, and save the following as capture-puppeteer.mjs.

npm install puppeteer
import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({ headless: true });
try {
  const page = await browser.newPage();
  await page.setViewport({ width: 1440, height: 900, deviceScaleFactor: 1 });

  await page.goto('https://example.com', {
    waitUntil: 'networkidle2',
    timeout: 60_000,
  });

  await page.screenshot({
    path: 'puppeteer-full-page.png',
    fullPage: true,
    type: 'png',
  });
} finally {
  await browser.close();
}

Run it with node capture-puppeteer.mjs. As with Playwright, a network-idle wait can be a poor fit for pages with persistent connections or polling. Prefer a known page-specific readiness condition when the page behavior requires it.

Capture to data

When the screenshot call has no path, Puppeteer returns the image data to the caller. This is useful when the next step is processing or upload rather than writing a local file. Puppeteer also documents ElementHandle.screenshot() for capturing one element.

See the official Puppeteer screenshots guide and ScreenshotOptions API reference for the options supported by your installed version.

Compare the options that affect your workflow

Full page, viewport, element, or clip

  • Use fullPage: true for the scrollable page.
  • Leave it false or unset for a viewport screenshot.
  • Use an element screenshot when only a component matters. This can avoid producing a very tall image for a small target.
  • Use clipping when you need a defined rectangle. Check the framework’s current API for coordinate and scaling behavior.

Format, quality, and transparency

Both APIs expose image type choices and transparent-background behavior. JPEG quality is relevant when using JPEG; PNG is commonly useful for sharp interface details and lossless output. Playwright documents quality controls and masking in its screenshot API. Puppeteer documents quality where applicable. Verify exact option names and behavior against the version you install, especially if your pipeline depends on transparency or image encoding.

Viewport and device scale

Set the viewport before navigation or capture if screenshots are compared over time. Device scale affects pixel dimensions and can affect the appearance of the output. Record the viewport, device scale, browser build, and framework version with your baseline so that later changes are interpretable.

Wait conditions and page readiness

Navigation wait conditions such as load, DOM content loaded, or network idle answer different questions. A page can continue changing after navigation completes. For a reliable capture, wait for a meaningful selector or application state, and handle lazy-loaded material deliberately. If scrolling is required to trigger lazy images, use a controlled scroll-and-wait procedure before the final capture, then return to the intended scroll position if the workflow needs it. Validate the output rather than treating a successful API call as proof of completeness.

How to choose

  1. Use the framework already in your test stack. For one screenshot call, the documented full-page option is essentially the same.
  2. Check integration needs. Compare your existing browser setup, test fixtures, selectors, and deployment environment.
  3. Check output needs. Decide whether you need a file or in-memory bytes, a full page or element, clipping, format, quality, transparency, or masking.
  4. Check the page behavior. Test lazy content, sticky elements, animation, and very long pages using representative URLs.
  5. Keep comparison conditions fixed. Run captures with the same browser build, operating system, viewport, device scale, settings, and readiness logic.
  6. Benchmark only your real workload. Measure elapsed time, memory use, output dimensions, and failures across representative pages if those determine your choice.

There is no controlled Puppeteer-versus-Playwright benchmark or maximum full-page dimension in the official references reviewed. Do not treat anecdotal timing or one site’s output as a general winner.

Reproducible screenshot baselines

Playwright warns that rendering can vary with the host operating system, browser version, settings, hardware, power source, headless mode, and other environmental factors. Use the same environment that generated the baseline when possible. For either framework, pin dependencies and browser versions in the capture job, use a stable viewport and device scale, and avoid comparing captures made under different fonts, locale, timezone, or page data.

For visual checks, capture only after fonts and important images are ready, disable or stabilize animations where the application permits it, and mask genuinely dynamic regions when your comparison tool supports that. Store enough metadata to reproduce a failure: URL, timestamp, framework and browser versions, viewport, wait condition, and error details.

Troubleshooting

Symptom Likely cause Fix
Screenshot is only the visible viewport fullPage was omitted or false Set fullPage: true in the screenshot call.
Screenshot is blank or shows an error page Navigation failed, timed out, or the site returned an interstitial Check the navigation response and page URL, raise the timeout only when justified, and wait for a page-specific ready state.
Images or lower-page content are missing Lazy loading has not been triggered, or capture began before assets were ready Scroll through the page in a controlled way, wait for the relevant images or selector, then capture and inspect.
Capture hangs waiting for network idle The page polls, streams, or holds connections open Use a less restrictive navigation wait and explicitly wait for the content needed in the screenshot.
Text or layout differs from the baseline Browser, OS, fonts, viewport, scale, settings, or headless environment changed Match the baseline environment and capture configuration; inspect the page data and fonts too.
Sticky header appears repeatedly or overlaps content Full-page behavior and the page’s sticky positioning interact Inspect the rendered result; consider a targeted element or clip capture, or adapt the page for the screenshot run.
Output file is missing Wrong working directory, unwritable path, or capture failed before saving Use an explicit output path, check process permissions, and surface screenshot-call errors.
Browser fails to launch in a container Required browser files or system dependencies are unavailable, or the runtime is misconfigured Install the framework’s supported browser and required dependencies for the environment, and review launch errors before changing sandbox settings.

Performance, reliability, and cost

Both approaches require a browser process and page navigation. Full-page images can consume more time and memory as page length and pixel density increase, but the reviewed official references provide no comparative benchmark or maximum page height. Large captures should be tested with the pages and environment you will use in production. Reuse browser processes where appropriate in a service, isolate pages or contexts according to your concurrency and state needs, and close resources in cleanup paths so failed captures do not leave browsers running.

For reliability, set navigation timeouts, handle rejected navigation and screenshot calls, record failure details, and retry only transient failures with a bounded policy. A retry will not fix a persistent CAPTCHA, unavailable page, or selector that never appears. Browser-based DIY capture has infrastructure costs in compute, storage, and maintenance; the exact cost depends on your deployment and volume, so measure it against your own workload.

Or skip the browser setup

ScreenshotNeo is the first hosted screenshot API alternative to try when you want a single request instead of maintaining browser capture code. Its API returns a screenshot or PDF, and its API documentation describes the request options. A basic full-page request can be made with:

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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);

ScreenshotNeo removes cookie and consent banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, and failed loads are never billed; an MCP server lets AI agents take screenshots; and 1,000 screenshots per month are free with no card, with paid plans starting at $5 for 3,000. The API also supports full-page capture with lazy images loaded, custom viewport and device presets, CSS selectors, wait controls, and other capture options. See the docs for the exact parameters and response headers.

Create a free ScreenshotNeo account for 1,000 screenshots a month, with no card required.

FAQ

Are the Puppeteer and Playwright full-page calls interchangeable?

The basic call shape is the same, but that does not establish identical behavior under every browser or page condition. Check each framework’s API for your installed version and validate representative pages.

Does full-page capture include content below the fold?

It is intended to capture the scrollable page beyond the visible viewport. Content that only loads after scrolling may still need to be triggered and awaited.

Which framework is faster?

The official documentation reviewed does not establish a general speed winner. Benchmark the pages, versions, and execution environment you actually use.

Can I capture a page without saving a PNG file?

Yes. Both frameworks can return screenshot data for further processing; Playwright explicitly documents a buffer. Omit the file path and use the returned data in your application.

Sources