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

For an automatic full-document screenshot in headless Chrome, use Puppeteer and set fullPage: true:

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

Puppeteer measures the rendered document and captures beyond the initial viewport. Chrome’s command-line --screenshot flag is different: it captures a window whose dimensions you specify, so a tall --window-size is not an automatic full-height measurement.

Choose the right capture method

There are two practical headless-Chrome interfaces for this job:

Interface Best for Full-document control Readiness and dynamic content
Puppeteer Scripts that navigate, wait, interact and capture Explicit fullPage: true; fullPage defaults to false You define waits, selectors and interactions in JavaScript
Chrome CLI One-off command-line captures with fixed dimensions --screenshot plus a chosen --window-size; no documented automatic document-height sizing --timeout is only a maximum wait; --virtual-time-budget can advance timer-driven code

Use Puppeteer when the page needs a scripted workflow or when the output must include the entire rendered document. Use the CLI when a fixed viewport is sufficient and you do not need browser interaction.

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

Capture the full page with Puppeteer

Install and launch Chromium

In a new project, install Puppeteer. Its package downloads a compatible browser unless your environment is configured to use an existing Chrome or Chromium executable.

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

Minimal JavaScript example

This script opens a URL, gives application code a short opportunity to render, and then captures the complete document.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();

  await page.setViewport({ width: 1440, height: 900, deviceScaleFactor: 1 });
  await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });

  // Replace this with a site-specific readiness check when necessary.
  await new Promise(resolve => setTimeout(resolve, 1000));

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

  await browser.close();
})();

Run it with node capture.js. The important setting is fullPage: true. If you omit it, Puppeteer captures only the current viewport because the option defaults to false.

Wait for the content that matters

Navigation finishing does not establish that every application request, timer, image or client-side component has finished. There is no universal readiness condition for every site. Prefer a condition that describes your target page:

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.
  • Wait for a stable element with await page.waitForSelector('.article-body').
  • Wait for an application-specific status, such as a “loaded” marker, with page.waitForFunction.
  • Use a short delay only when the page’s rendering behavior is known and repeatable.
  • For content loaded by scrolling, scroll deliberately before the screenshot so lazy-loading code gets a chance to run.

Do not treat a generic timeout as proof that all asynchronous work is complete. The correct wait is part of the target site’s behavior.

Understand fullPage, clipping and viewport capture

fullPage versus captureBeyondViewport

Puppeteer exposes both options, but they express different intentions. fullPage requests the entire page and is the clearest setting for an auto-height document screenshot. captureBeyondViewport controls capture outside the viewport; its documented default is false when no clip is supplied and true when a clip is supplied. It is not a replacement for the ordinary full-document fullPage: true workflow.

Capture a region instead

If you need one component rather than the document, use a CSS-based bounding box and clip. That is a separate task from auto-height capture. Keep the viewport and clipping rectangle explicit so a later stylesheet change does not silently alter the output.

const box = await page.$eval('#invoice', element => {
  const r = element.getBoundingClientRect();
  return { x: r.x, y: r.y, width: r.width, height: r.height };
});

await page.screenshot({ path: 'invoice.png', clip: box });

Use Chrome’s headless command line

Chrome documents --screenshot together with a selected window size. Replace chrome with the executable name installed on your system, such as google-chrome or a platform-specific path.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
chrome --headless --screenshot --window-size=412,892 https://example.com/

This captures a 412-by-892 window. Increasing the height gives you a taller fixed viewport; it does not ask Chrome to discover the page’s total document height.

Control waiting and virtual time

--timeout places a maximum limit on how long Chrome waits before capture. Capture can still occur while the page is loading when that limit is reached, so it is a timing cap rather than a readiness guarantee.

chrome --headless --screenshot --window-size=1440,900 --timeout=15000 https://example.com/

For pages whose output changes because of JavaScript timers, Chrome documents --virtual-time-budget to fast-forward virtual time before capture:

chrome --headless --screenshot --window-size=1440,900 --virtual-time-budget=5000 https://example.com/

Virtual time does not replace checking that the page’s own network requests and rendering have completed.

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

Make dynamic pages capture reliably

Lazy-loaded images

Images that load only after entering the viewport may be absent from a first pass. In Puppeteer, scroll through the document before taking the final screenshot, then wait for the images or a page-specific completion signal.

await page.evaluate(async () => {
  await new Promise(resolve => {
    let y = 0;
    const step = 500;
    const timer = setInterval(() => {
      window.scrollBy(0, step);
      y += step;
      if (y >= document.body.scrollHeight) {
        clearInterval(timer);
        window.scrollTo(0, 0);
        resolve();
      }
    }, 50);
  });
});

await new Promise(resolve => setTimeout(resolve, 500));
await page.screenshot({ path: 'lazy-loaded.png', fullPage: true });

The scroll distance and final delay are site-dependent. A page with infinite scroll may keep increasing its height, so define a stopping rule instead of waiting for an impossible “end.”

Sticky headers and fixed overlays

A sticky header can appear repeatedly in a long capture because it remains fixed while the document is rendered. Whether that is desirable is a design decision. If the page has a print stylesheet or a documented “reader” mode, use that mode. Otherwise, hide or restyle the element with page-specific CSS before capture and record the change in your script.

Animations and carousels

Animated elements can produce inconsistent screenshots. Pause them with custom CSS, or wait until a stable state exposed by the application. Do not assume a fixed delay will select the same animation frame on every run.

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

Very tall documents

Full-page output can become a very large bitmap. Keep an eye on memory, image dimensions and downstream limits. If a consumer accepts paginated output, a PDF or a sequence of viewport captures may be more practical than one extremely tall PNG.

Run a production-oriented Puppeteer capture

This version adds a navigation timeout, a selector-based readiness check and explicit cleanup. Adjust the selector and URL for the application you control.

const puppeteer = require('puppeteer');

async function capture(url, output) {
  const browser = await puppeteer.launch({ headless: true });
  try {
    const page = await browser.newPage();
    await page.setViewport({ width: 1365, height: 768, deviceScaleFactor: 1 });
    await page.goto(url, {
      waitUntil: 'domcontentloaded',
      timeout: 30000
    });
    await page.waitForSelector('main', { timeout: 30000 });

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

capture('https://example.com', 'example-full.png')
  .catch(error => {
    console.error(error);
    process.exitCode = 1;
  });

The Puppeteer ScreenshotOptions reference is versioned 25.12.0 in the cited documentation. Keep the installed Puppeteer and browser versions aligned, and verify behavior after upgrades.

Troubleshoot missing or incorrect captures

Only the viewport is present

Cause: fullPage was omitted or set to false. Fix: set fullPage: true in page.screenshot. A tall CLI window is not equivalent to this option.

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

Lower-page content is blank

Cause: lazy loading, delayed client rendering or an application request that had not completed. Fix: wait for a meaningful selector, scroll to trigger lazy loading, then wait for the resulting images or status marker.

The screenshot stops while the page is still loading

Cause: the CLI timeout was reached. Fix: increase --timeout only after defining what “ready” means for the page; a larger number alone cannot guarantee readiness.

Output differs between runs

Cause: animations, rotating content, ads, time-dependent code or nondeterministic data. Fix: freeze animations where appropriate, use stable test data, set a consistent viewport and timezone, and wait for a deterministic application signal.

Chrome fails to start in a server or container

Cause: an unavailable executable, missing shared libraries, sandbox restrictions or insufficient memory. Fix: confirm the browser path, run the same executable interactively, inspect the launch error, and provide the runtime dependencies required by your operating system. Do not hide launch errors by ignoring the rejected promise.

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

The image is too large for the next system

Cause: a long document multiplied by a large viewport or device scale factor. Fix: lower the viewport width or device scale factor, use JPEG/WebP when acceptable, split the document, or produce a PDF for a paginated workflow.

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

Performance, reliability and cost considerations

A new browser process for every URL is simple but expensive. For batches, reuse one browser process and create isolated pages, while closing each page after capture. Limit concurrency to the memory available on the runner. Record the target URL, viewport, browser version, wait condition and output dimensions so a changed screenshot can be diagnosed.

Full-page screenshots are rendered images, not a semantic representation of the page. If you need searchable, paginated output, compare the screenshot workflow with PDF generation. For visual regression, keep all capture inputs stable: viewport, device scale factor, fonts, locale, timezone, authentication state and data.

Puppeteer itself does not charge per screenshot; your costs are the browser runtime, compute, storage and engineering time. A hosted capture service can shift those operational concerns to an API, but you still need to specify readiness and output requirements.

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

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. It removes cookie and consent banners, newsletter popups and chat widgets before capture; bot checks, blank pages, timeouts, failed loads and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients.

For a full-page shot, call the API with the target URL:

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

See the ScreenshotNeo documentation for authentication and option details. Equivalent Python and Node.js requests are:

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://example.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
const data = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('shot.webp', data);

Options relevant to auto-height captures

  • Full-page capture with lazy images loaded.
  • Wait for a selector, a delay or network idle.
  • Custom JavaScript and CSS, clicks before capture, and selectors to hide.
  • Viewport presets, arbitrary viewport sizes and retina scale.
  • Dark mode, timezone, geolocation, headers, cookies, user agent and Authorization.
  • Blocking for ads, trackers, requests or resource types.
  • Image resizing, transparent backgrounds, caching with a chosen TTL, signed links, asynchronous jobs with signed webhooks and bulk capture of up to 100 URLs per call.
  • PDF paper size, margins, landscape mode and page ranges.

Every feature is included on every plan. The current allowances and listed prices are:

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.
Plan Allowance Price
Free 1,000 shots per month $0; no card
Starter 3,000 shots $5
Growth 15,000 shots $15
Pro 60,000 shots $39
Scale 250,000 shots $99
Business 1,000,000 shots $249

Yearly billing gives two months free. Start with 1,000 free screenshots a month with no card, then choose a paid plan starting at $5 for 3,000 shots if your volume requires it.

Frequently asked questions

Does a full-page screenshot automatically load every infinite-scroll item?

No. Infinite-scroll pages have no fixed end until the application stops adding content. Scroll with an explicit stopping rule or capture a bounded state.

Should I use PNG, JPEG or WebP?

PNG preserves sharp text and flat graphics well. JPEG and WebP can reduce output size when small compression differences are acceptable; choose based on the system consuming the file.

Can I combine a clip with full-page capture?

They represent different goals: fullPage requests the document, while clip defines a region. Use the option that matches whether you need the page or one bounded element.

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

Frequently Asked Questions

Does a full-page screenshot automatically load every infinite-scroll item?

No. Infinite-scroll pages have no fixed end until the application stops adding content. Scroll with an explicit stopping rule or capture a bounded state.

Should I use PNG, JPEG or WebP?

PNG preserves sharp text and flat graphics well. JPEG and WebP can reduce output size when small compression differences are acceptable; choose based on the system consuming the file.

Can I combine a clip with full-page capture?

They represent different goals: fullPage requests the document, while clip defines a region. Use the option that matches whether you need the page or one bounded element.

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.