ScreenshotNeo

BlogHow-to

Web Page to PNG: Complete Developer Guide

Learn how to convert any web page to PNG with Playwright, Puppeteer, Chrome Headless, or ScreenshotNeo—including full-page and element captures.

By the ScreenshotNeo team1 October 20267 min read

Web Page to PNG: Complete Developer Guide

Yes. A browser automation tool can render a web page and save the result as a PNG. Use a viewport screenshot when you need only the visible browser area, or enable full-page capture when you need the entire scrollable document. Playwright and Puppeteer provide programmable APIs; Chrome Headless provides a command-line option.

This guide covers complete examples, element and clipped captures, output scale, lazy-loaded content, transparent backgrounds, troubleshooting, and a hosted alternative with ScreenshotNeo.

1. Choose the right capture method

Need Recommended method Why
Automated screenshots in an application Playwright Supports viewport, full-page, locator, and byte-buffer captures.
Existing Chromium automation code Puppeteer Supports full-page screenshots, clipping, PNG, JPEG, WebP, and buffers.
A one-off command Chrome Headless The --screenshot flag writes a PNG from the shell.
No browser installation or maintenance ScreenshotNeo A single HTTP request returns a rendered PNG, JPEG, WebP, or PDF.
A screenshot pipeline renders a URL into a PNG image.
A screenshot pipeline renders a URL into a PNG image.

2. Convert a web page to PNG with Playwright

Install Playwright and its browser binaries:

npm install -D playwright
npx playwright install chromium

Create screenshot.mjs:

import { chromium } from 'playwright';

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

Run it with node screenshot.mjs. The documented Playwright example uses page.screenshot({ path: 'screenshot.png' }); PNG is selected by the .png path and the explicit type above. See the Playwright screenshots documentation.

Capture the entire scrollable page

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

fullPage: true captures the full scrollable page instead of only the current viewport. Long pages may be tall and consume substantial memory.

Capture one element

const article = page.locator('main article');
await article.screenshot({ path: 'article.png', type: 'png' });

Use a stable selector. If the locator matches multiple elements, Playwright will require you to narrow it to one.

Return PNG bytes instead of writing a file

const png = await page.screenshot({ type: 'png' });
// png is a Buffer that can be uploaded, hashed, or processed.

Control output scale

const browser = await chromium.launch();
const cssPixels = await browser.newPage({ deviceScaleFactor: 1 });
const retina = await browser.newPage({ deviceScaleFactor: 2 });

Playwright documents scale: "css" as one image pixel per CSS pixel and scale: "device" as one pixel per device pixel. Device-scale output can be twice as large or larger on high-DPI displays; choose it when you need retina density and CSS scale when predictable dimensions matter. See the Page API.

3. Convert a web page to PNG with Puppeteer

Install Puppeteer:

npm install puppeteer

Create puppeteer-shot.mjs:

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({ width: 1440, height: 900, deviceScaleFactor: 1 });
await page.goto('https://example.com', { waitUntil: 'networkidle2' });
await page.screenshot({ path: 'page.png', type: 'png' });
await browser.close();

Puppeteer documents PNG as the default image type. When a path is supplied, the extension can infer the format. JPEG and WebP quality settings do not apply to PNG. See Page.screenshot() and the ScreenshotOptions reference.

Full-page, clipped, and transparent captures

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

await page.screenshot({
  path: 'region.png',
  type: 'png',
  clip: { x: 100, y: 200, width: 800, height: 600 }
});

await page.screenshot({ path: 'transparent.png', type: 'png', omitBackground: true });

Use fullPage for the whole document, clip for a pixel rectangle, and omitBackground when the page supports a transparent background.

4. Convert a web page to PNG with Chrome Headless

For a shell-only workflow, Chrome’s Headless reference documents --screenshot. Pair it with --window-size to control the viewport:

google-chrome --headless --disable-gpu \
  --window-size=1440,900 \
  --screenshot=page.png \
  https://example.com

The command writes page.png in the current directory (or to the path supplied to the flag, depending on the installed Chrome version). Read the Chrome Headless command-line reference for the flags available in your version.

5. Make captures reliable

Wait for the content you need

networkidle helps with pages that load data after navigation, but it is not a guarantee that every image or animation is ready. For a known component, wait for its selector:

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

For infinite scroll or lazy images, scroll progressively before taking a full-page screenshot:

await page.evaluate(async () => {
  await new Promise((resolve) => {
    let y = 0;
    const step = 600;
    const timer = setInterval(() => {
      window.scrollBy(0, step);
      y += step;
      if (y >= document.body.scrollHeight) {
        clearInterval(timer);
        resolve();
      }
    }, 100);
  });
});
await page.screenshot({ path: 'lazy-loaded.png', fullPage: true, type: 'png' });

Freeze layout-changing effects

await page.addStyleTag({ content: `
  *, *::before, *::after {
    animation: none !important;
    transition: none !important;
    caret-color: transparent !important;
  }
` });

Fonts, responsive breakpoints, consent dialogs, ads, and personalization can change pixels between runs. Set the same viewport, locale, timezone, cookies, and user agent when reproducibility matters.

Viewport versus full-page dimensions

A viewport screenshot has the exact width and height you configure. A full-page screenshot can be thousands of pixels tall. If a downstream system has a maximum image dimension, capture sections or use a PDF workflow instead.

6. Troubleshooting

Symptom Likely cause Fix
Only the visible screen is saved Full-page mode is disabled. Set fullPage: true in Playwright or Puppeteer.
PNG is blank or mostly white The page has not rendered, requires JavaScript, or returned an error page. Wait for a meaningful selector, inspect the response status, and capture after application data is present.
Images are missing Lazy loading has not been triggered, or image requests failed. Scroll the document, wait for image selectors, and check network errors.
Text differs between runs Fonts, animations, locale, time, or personalized content changed. Disable animations and fix viewport, locale, timezone, cookies, and user agent.
Element screenshot throws a locator error The selector matches zero or multiple elements. Wait for the element and use a unique selector.
Capture is too large Device scale or a very tall full-page document multiplies pixels. Use CSS scale, a smaller viewport, element captures, or split the page.
Chrome command fails The executable name or headless flags differ by platform/version. Run the installed Chrome binary directly and check its --help output.

7. Performance, reliability, and cost

  • Reuse browsers: launch one Playwright or Puppeteer browser and create pages for multiple URLs. Browser startup is expensive compared with a new page.
  • Limit concurrency: too many simultaneous pages increase CPU, memory, and site load. Use a queue and a small worker pool.
  • Choose the smallest output: viewport or element PNGs are faster and smaller than very tall full-page images. CSS scale reduces pixel count.
  • Set timeouts: fail clearly when a site never finishes loading, and record the URL and stage that timed out.
  • Cache deterministic captures: if the page and rendering inputs have not changed, avoid repeating work. Never cache private pages without an appropriate access policy.
  • PNG size: PNG is lossless. For photographic pages, JPEG or WebP may be smaller, but PNG is preferable for text, diagrams, and transparency.

8. Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF, so your application does not need to install or maintain a browser.

Consent banners and overlays can be removed before capture.
Consent banners and overlays can be removed before capture.

See the ScreenshotNeo API documentation for the complete option list. Basic PNG request:

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 fs = require('node:fs');
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(`HTTP ${res.status}`);
fs.writeFileSync('shot.webp', Buffer.from(await res.arrayBuffer()));

ScreenshotNeo can capture full pages with lazy images loaded, one CSS-selected element, dark mode, device presets or custom viewports, retina scale, PDFs, custom CSS and JavaScript, clicks, selector or network-idle waits, blocked ads and trackers, custom headers and cookies, user agents and Authorization, timezone and geolocation, transparent backgrounds, resizing, caching with a chosen TTL, signed links, asynchronous jobs with signed webhooks, bulk capture for up to 100 URLs per call, usage data, and an OpenAPI specification.

Cookie banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed; response headers identify the page verdict and whether the request was billed. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

9. FAQ

Can I convert a page to PNG without JavaScript?

Yes, Chrome Headless can capture a URL from the command line. Pages that depend on client-side rendering usually need Playwright, Puppeteer, or a rendering API.

How do I save only the visible browser area?

Omit fullPage and set the viewport dimensions. In Puppeteer, do not provide fullPage: true.

How do I capture a specific component?

Use a Playwright locator screenshot or Puppeteer’s clip rectangle. A locator follows the element’s rendered bounds; a clip uses fixed page coordinates.

Why is my PNG different on a server?

Fonts, device scale, viewport width, timezone, locale, cookies, animations, and personalized responses can all change rendered pixels. Make those inputs explicit.

Should I use PNG, JPEG, or WebP?

Use PNG for lossless text, interfaces, diagrams, and transparency. Use JPEG or WebP when smaller photographic output matters and transparency is unnecessary.