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

A Node.js screenshot is a visual image of a web page rendered by a browser that Node.js controls. It is normally created with an automation library such as Puppeteer or Playwright—not a V8 heap snapshot, which is diagnostic memory data. The shortest reliable workflow is to launch a browser, open a page, wait for the page to reach an appropriate ready state, save the screenshot, and close the browser.

This guide shows complete Puppeteer and Playwright examples, explains viewport, full-page, element and in-memory captures, covers important options and failure modes, and then shows a one-request alternative with ScreenshotNeo.

What “Node.js screenshot” means

In web-development discussions, a Node.js screenshot usually means an image of a webpage produced by a browser controlled from JavaScript running in Node.js. Puppeteer and Playwright automate a real browser engine, so the result includes rendered HTML, CSS, fonts, images and JavaScript state.

That is different from a Node.js or V8 heap snapshot. A heap snapshot describes objects in process memory for debugging; it is not a picture of a page.

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

Capture a webpage with Puppeteer

Install Puppeteer in a Node.js project, then create a module file such as screenshot.mjs:

npm install puppeteer
import puppeteer from 'puppeteer';

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

Run it with node screenshot.mjs. The file is written relative to the process working directory. The Puppeteer screenshots guide uses networkidle2 in its basic navigation example. Treat that as an example, not a universal readiness rule: a dynamic application may need a selector, application state or another condition before capture.

Use a different target URL

Replace the URL passed to page.goto(). For pages that redirect, require authentication, or load data after navigation, wait for the state that means the content you need is actually present.

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

A selector wait is only appropriate when that selector reliably represents readiness on your page. A fixed delay can help with a known animation, but it is less precise than waiting for a meaningful page condition.

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

Choose the capture scope

Requirement Puppeteer approach Result
Visible viewport page.screenshot({ path: 'shot.png' }) The currently visible browser area.
Entire scrollable page page.screenshot({ path: 'shot.png', fullPage: true }) A capture of the full page height; Puppeteer documents fullPage as false by default.
One component const el = await page.$('.card'); await el.screenshot({ path: 'card.png' }); Only the selected element.
Rectangular region page.screenshot({ path: 'crop.png', clip: { x: 20, y: 80, width: 500, height: 300 } }) A defined viewport rectangle.
Image bytes const bytes = await page.screenshot() Bytes for processing or uploading instead of immediate disk output.

Element screenshots require the element to exist and be visible. If an element is inside a scrollable container or changes size after loading, wait for its final state before capturing.

Important Puppeteer screenshot options

The current ScreenshotOptions reference documents these controls:

  • path: optional output path. The image type is inferred from the extension; a relative path is resolved from the process working directory. Without a path, the screenshot is returned rather than saved.
  • Format: PNG is the default. JPEG or WebP can be selected through the format options supported by your installed Puppeteer version.
  • fullPage: false by default; set it to true for the complete scrollable page.
  • clip: a rectangular capture area.
  • omitBackground: enables transparent capture when the page and output format support it.
  • quality: a value from 0 to 100 for lossy formats; it does not apply to PNG.
  • Encoding: the API can return image bytes, or a base64 string when its base64 encoding option is used.

Defaults and option names can change. The Page.screenshot API page displayed Puppeteer version 25.12.0 on September 29, 2026, so verify the documentation for the version installed in your project before depending on a default.

Set a predictable viewport

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

Controlling the viewport makes local and automated captures more repeatable. If responsive breakpoints matter, create separate captures at the widths you support.

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

Playwright alternative

Playwright offers the same broad capture scopes. Install it with npm install -D playwright and use:

import { chromium } from 'playwright';

const browser = await chromium.launch();
try {
  const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
  await page.goto('https://example.com', { waitUntil: 'networkidle' });
  await page.screenshot({ path: 'playwright.png', fullPage: true });
} finally {
  await browser.close();
}

Playwright also returns bytes when no path is supplied and supports element screenshots:

const image = await page.screenshot();
await page.locator('.pricing-card').screenshot({ path: 'pricing-card.png' });

See the Playwright screenshots guide. Do not assume every option name or default is interchangeable with Puppeteer; consult the documentation for the library and version in your project. The available documentation establishes overlapping features, not a universal speed or accuracy winner.

Make page readiness explicit

Wait for a meaningful selector

await page.goto('https://example.com/report', { waitUntil: 'domcontentloaded' });
await page.waitForSelector('#report-chart');
await page.screenshot({ path: 'report.png' });

Wait for a known delay

await page.goto('https://example.com/animated', { waitUntil: 'networkidle2' });
await new Promise(resolve => setTimeout(resolve, 1000));
await page.screenshot({ path: 'animated.png' });

Use a delay only when you understand the page’s timing. Network-idle events can be unsuitable for applications that keep connections open, and a page can become network-idle before client-rendered content appears.

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

Save, process or upload the image

With Puppeteer, capture without path to obtain image data, then write it yourself:

import { writeFile } from 'node:fs/promises';
const bytes = await page.screenshot();
await writeFile('shot.png', bytes);

This pattern lets you send bytes to object storage, attach them to a test report, or pass them to an image-processing pipeline without creating an intermediate file. For large full-page images, account for memory use and avoid retaining many buffers at once.

Common errors and fixes

“Cannot find package puppeteer”

Install the dependency in the project where the script runs: npm install puppeteer. Check that you are running the command from the same project directory and that your import style matches your module configuration.

Browser fails to launch in CI or a container

Check the browser installation, executable permissions and the runtime’s sandbox restrictions. Use the launch settings required by your CI environment rather than copying flags blindly; disabling security features has security implications.

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.

The screenshot is blank or missing content

  • Wait for a selector that appears only after rendering completes.
  • Confirm the URL, redirects and authentication state.
  • Increase the viewport or use fullPage: true when content is below the fold.
  • Check whether an overlay, consent dialog or lazy-loaded image covers the content.

Images or fonts are not ready

Wait for the page condition that your application uses to signal completion. A generic network-idle event is not guaranteed to cover every font, image or client-side render.

Element screenshot throws an error

Verify the selector, wait for the element, and ensure it is visible and attached to the document. If the element is inside a closed shadow root or cross-origin frame, ordinary page selectors may not reach it.

Full-page capture is unexpectedly large

Full-page images can be tall and memory-intensive. Capture a specific element or clip a region when that is all you need; choose JPEG or WebP when a lossy format is acceptable.

Performance, reliability and cost considerations

  • Reuse browsers: launching a browser for every URL adds startup overhead. In a service, reuse a browser process while creating and closing pages carefully.
  • Control concurrency: too many simultaneous pages can exhaust CPU, memory or file descriptors. Set a queue and measure your workload.
  • Keep captures deterministic: set viewport dimensions, wait for a defined readiness condition, and control authentication and data state.
  • Handle cleanup: put browser.close() in a finally block so failures do not leave browser processes running.
  • Expect page-specific behavior: the official guides document APIs and examples, but no source establishes one universal readiness rule, benchmark or accuracy advantage for all sites.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP or PDF. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets; each cleanup step can be turned off. Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing, and response headers identify 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.

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.

For Node.js, use the same request from your application:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', image));

See the ScreenshotNeo documentation for parameters and response details. The service includes full-page and element capture, device and viewport controls, retina scale, PDF settings, custom CSS and JavaScript, clicks, waits, blocked requests, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, selectable cache TTLs, signed image links, asynchronous webhooks, bulk capture for up to 100 URLs per call, a usage API and an OpenAPI specification. Parameter names used by other screenshot APIs also work, which can simplify migration.

The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is on every plan, and yearly billing gives two months free. Create a free ScreenshotNeo account to try it without a card.

Frequently asked questions

Is a Node.js screenshot the same as a heap snapshot?

No. A screenshot is a rendered page image; a heap snapshot is diagnostic memory data from the JavaScript runtime.

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

Should I use Puppeteer or Playwright?

Choose the library already used by your project or whose browser and runtime support fit your needs. Both document viewport, full-page, element and byte-returning screenshots; their exact options and defaults differ.

Can I capture a page without saving a file?

Yes. Omit the path and keep the returned image bytes, or request the documented base64 form in Puppeteer.

Why does a screenshot differ between runs?

Differences usually come from viewport size, asynchronous rendering, changing data, fonts, animations or resource timing. Make those inputs explicit and wait for a page-specific ready condition.

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.