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

Use Puppeteer’s page-level screenshot() method with fullPage: true. The option is false by default, so setting it explicitly tells Chromium to capture the page’s full scrollable content instead of only the visible viewport:

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

The complete script below launches a browser, opens a URL, waits for navigation, writes a PNG, and closes the browser even if capture fails.

Minimal full-page screenshot script

Create a JavaScript file such as full-page.js, install Puppeteer in your project, and run the file with Node.js.

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: 'screenshot.png', fullPage: true });
} finally {
  await browser.close();
}

When the script finishes, screenshot.png is created in the process’s current directory. The image type is inferred from the filename extension. If you omit path, Puppeteer returns the screenshot data instead of saving a file.

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

What fullPage: true actually does

Page.screenshot() is Puppeteer’s page-level capture API. With fullPage: true, it captures the page’s full rendered height rather than just the current viewport. Because fullPage defaults to false, leaving the option out produces a viewport screenshot.

Full-page capture is based on what the browser has rendered at the time of the call. It does not automatically prove that every application request, animation, carousel, or lazy-loaded image has finished. Choose a wait condition that matches the site you are capturing before taking the shot.

Control navigation and page readiness

Navigation and capture are separate operations. A reliable script makes the navigation wait explicit, then adds any page-specific readiness check that the target requires.

Wait for a navigation state

import puppeteer from 'puppeteer';

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

The appropriate waitUntil value depends on the page. A document-ready state may be enough for a static document; a client-rendered application may need an explicit selector or a deliberate delay after navigation. No single generic network-idle condition guarantees that every lazy image or application-specific widget has finished rendering.

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

Wait for a selector

await page.goto('https://example.com/dashboard', { waitUntil: 'domcontentloaded' });
await page.waitForSelector('[data-page-ready]');
await page.screenshot({ path: 'dashboard.png', fullPage: true });

Waiting for a selector is usually more meaningful than waiting an arbitrary number of milliseconds when the application exposes a stable “ready” element. If the selector never appears, Puppeteer throws a timeout error; handle that as a failed capture rather than saving a misleading partial image.

Wait for a known delay when necessary

await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await new Promise(resolve => setTimeout(resolve, 1500));
await page.screenshot({ path: 'screenshot.png', fullPage: true });

A delay can allow a predictable animation or deferred request to complete, but it is less robust than waiting for a concrete DOM condition. Use it only when the page gives you no better readiness signal.

Set the viewport before navigation

Puppeteer viewport dimensions are measured in CSS pixels. Set the viewport before calling goto() when the screenshot must represent a particular desktop or mobile layout.

const page = await browser.newPage();
await page.setViewport({ width: 1440, height: 900, deviceScaleFactor: 1 });
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.screenshot({ path: 'desktop.png', fullPage: true });
  • width and height: CSS-pixel viewport dimensions that influence responsive breakpoints and layout.
  • deviceScaleFactor: the rendering scale; Puppeteer’s default is 1. A higher value changes the bitmap scale and resource requirements.
  • Mobile or touch settings: changing mobile or touch-related viewport properties can reload a page, so configure them before navigation whenever possible.

Do not promise an exact output bitmap size from CSS dimensions alone. The final image also depends on the browser’s rendering configuration and device scale factor.

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

Choose the output and destination

Save an image to disk

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

The extension determines the image type for a file saved with path. Use a matching extension such as .png, .jpeg, or .webp. Keep the output path explicit in automated jobs so a working-directory change does not put files somewhere unexpected.

Keep the bytes in memory

const bytes = await page.screenshot({ fullPage: true });
// bytes is a Buffer that you can upload or process in your application

When you need a text representation instead, request Base64 encoding:

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

Omitting path means Puppeteer does not write a file automatically. Your code is responsible for storing or returning the resulting bytes.

Capture only a region when a full page is not the goal

fullPage and clip solve different problems. Use fullPage: true for the complete scrollable page. Use clip when the deliverable is a defined rectangle.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
await page.screenshot({
  path: 'hero.png',
  clip: { x: 0, y: 0, width: 1200, height: 650 }
});

Puppeteer documents captureBeyondViewport as false when no clip is provided and true when a clip is provided. For the normal whole-page case, explicitly use fullPage: true; add a clip only when you intentionally want a region.

Capture one element

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

ElementHandle.screenshot() scrolls the element into view when needed and captures that element rather than the entire document. This is preferable for a component, chart, or product card that should not include the rest of the page.

Generate a PDF instead

await page.pdf({
  path: 'page.pdf',
  format: 'A4',
  printBackground: true
});

Use Page.pdf() when the intended deliverable is a printable document. PDF output follows print-oriented behavior and is not interchangeable with a pixel-for-pixel full-page image.

A production-friendly capture flow

The following pattern combines an explicit viewport, a navigation wait, a page-specific readiness check, and guaranteed cleanup. Replace the selector with one that your application controls.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import puppeteer from 'puppeteer';

const target = process.argv[2] ?? 'https://example.com';
const output = process.argv[3] ?? 'screenshot.png';

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  await page.setViewport({ width: 1365, height: 768, deviceScaleFactor: 1 });
  await page.goto(target, {
    waitUntil: 'domcontentloaded',
    timeout: 30000
  });
  await page.waitForSelector('body', { timeout: 10000 });
  await page.screenshot({ path: output, fullPage: true });
  console.log(`Saved ${output}`);
} finally {
  await browser.close();
}

Run it with node full-page.js https://example.com example.png. The try/finally block matters in CI and scheduled jobs: a navigation or selector timeout should not leave a browser process running.

Lazy-loaded content, animations, and very long pages

Lazy-loaded images

A page can contain images that load only after scrolling or after an application event. A full-page screenshot captures the rendered state; it does not guarantee that every lazy resource has been requested. If the site exposes a “load complete” signal, wait for it. Otherwise, inspect the page behavior and add a targeted readiness step rather than assuming that a generic network-idle setting covers every image.

Animations and changing content

Animated banners, rotating carousels, clocks, and personalized content can make two captures differ. Freeze or disable those effects in the page under test when deterministic output matters, and wait for the state you intend to document before calling screenshot().

Long documents

A full-page image can become very tall and expensive to hold in memory. If the destination only needs a section, capture an element or a clipped region instead. If the destination is a printable report, generate a PDF and choose paper and page settings rather than creating one giant bitmap.

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

Troubleshooting common failures

Symptom Likely cause Fix
Only the visible viewport is saved fullPage was omitted or set to false. Pass fullPage: true in the screenshot options.
The screenshot is blank or missing application content Capture ran before client-side rendering or a required request completed. Use waitUntil, then wait for a stable application selector or another page-specific ready signal.
Images are absent near the bottom Those images are lazy-loaded and were not rendered before capture. Trigger the page’s loading behavior and wait for its completion signal; do not assume one generic wait condition covers all lazy resources.
A selector wait times out The selector is wrong, the page failed to load, or the element appears only after an interaction. Verify the URL and selector, inspect the page state, and increase the timeout only after correcting the readiness condition.
The output file is not where expected path is relative to the process’s current working directory. Use an absolute path or log the working directory and resolved output path.
The file type is unexpected The filename extension does not match the requested format. Use .png, .jpeg, or .webp consistently with the intended output.
The capture job leaves Chromium running An exception occurred without browser cleanup. Launch inside a try/finally block and call browser.close() in finally.
A component screenshot is cropped incorrectly The element was not selected or the requested output is actually a page region. Check the element handle, let Puppeteer scroll it into view, or use clip for a rectangle.

Performance, reliability, and cost considerations

  • Set only the viewport you need. Wider layouts can render more content and trigger different responsive code paths.
  • Wait on application state, not a large universal delay. A targeted selector usually avoids both premature captures and unnecessary idle time.
  • Reduce capture scope when possible. Element and clipped screenshots use less memory than a very tall full-page bitmap.
  • Close every browser. Repeated jobs that skip cleanup can exhaust process or memory limits.
  • Separate navigation failures from visual failures. Log the URL, wait condition, output path, and thrown error so a missing page is not mistaken for a valid screenshot.
  • Do not infer dimensions from CSS alone. Record the viewport and device scale factor with the output when reproducibility matters.

Puppeteer itself does not charge per screenshot; your operational cost comes from the machine, browser runtime, storage, and any infrastructure used to run the jobs. The documentation does not establish a universal capture time or reliability percentage, so benchmark your own pages and workload instead of applying a generic number.

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

Or skip the browser setup

If you need an HTTP endpoint rather than a browser process to maintain, ScreenshotNeo returns a screenshot or PDF from one request. Its cleanup steps accept cookie or consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python

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)

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}`);

See the ScreenshotNeo API documentation for the complete parameter reference. It supports full-page captures with lazy images loaded, CSS-selector element capture, dark mode, 12 device presets or any viewport, retina scale, PDF paper and page-range settings, HTML/CSS-to-image, custom CSS and JavaScript, pre-capture clicks, hidden selectors, waits for selectors, delays or network idle, request and resource blocking, custom headers, cookies, user agents and Authorization, timezone and geolocation, transparent backgrounds, resizing, configurable-TTL caching, signed image links, asynchronous jobs with signed webhooks, bulk capture for up to 100 URLs per call, a usage API, and an OpenAPI specification. Parameter names used by other screenshot APIs are also accepted to ease migration. Every feature is available on every plan.

Plan Included screenshots Price
Free 1,000 per month $0, no card
Starter 3,000 $5
Growth 15,000 $15
Pro 60,000 $39
Scale 250,000 $99
Business 1,000,000 $249

Yearly billing gives two months free. ScreenshotNeo also provides an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients, so an AI agent can request captures without you wiring Puppeteer into the agent.

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

Start with 1,000 free screenshots a month with no card, or move to paid plans starting at $5 for 3,000 screenshots.

FAQ

Does a full-page screenshot include content outside the document’s rendered page?

No. It captures the page content that the browser has rendered. Content that appears only after an interaction, delayed request, or application-specific loading step must be made ready before the screenshot call.

Best Value
The SQL Programming Language: .
  • Used Book in Good Condition

Should I use a screenshot or a PDF for a report?

Use a screenshot when you need a visual image of the rendered page. Use page.pdf() when the output is intended for printing, pagination, paper size, margins, or page ranges.

Can I omit path in an automated service?

Yes. Without path, Puppeteer returns the image data, which you can upload, stream, or encode instead of writing a local file.

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

Frequently Asked Questions

Does a full-page screenshot include content outside the document’s rendered page?

No. It captures the page content that the browser has rendered. Content that appears only after an interaction, delayed request, or application-specific loading step must be made ready before the screenshot call.

Should I use a screenshot or a PDF for a report?

Use a screenshot when you need a visual image of the rendered page. Use page.pdf() when the output is intended for printing, pagination, paper size, margins, or page ranges.

Can I omit path in an automated service?

Yes. Without path, Puppeteer returns the image data, which you can upload, stream, or encode instead of writing a local file.

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.

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