Recommended Free Tools
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.
#1 Best Overall
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.
- 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.
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.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →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.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteVery 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.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →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.
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.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.
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.
| 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.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Frequently 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.
Quick Recap
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.

