ScreenshotNeo

BlogGuides

Screenshot Tool for Web Development

Choose the right screenshot tool for web development, automate full-page captures, and build reliable visual regression checks.

By the ScreenshotNeo team1 October 20267 min read

Playwright is the strongest general-purpose screenshot tool for web development. It captures a viewport, one element, or the full scrollable page; runs in scripts and CI; and supports PNG, JPEG, WebP, custom filenames, and CSS- or device-pixel scaling. Use Puppeteer when your project already uses its JavaScript browser automation API, DevTools for a one-off manual capture, and a hosted API when you need repeatable captures without maintaining browsers.

1. Choose the capture scope first

Need Best scope Why
Check what a user currently sees Viewport Matches the visible browser area.
Document a component or bug Element Keeps the relevant UI large and focused.
Archive a landing page or documentation page Full page Captures the complete scrollable document.
Compare releases Stable viewport or element Produces repeatable images for visual regression.

Decide whether coordinates should be interpreted in CSS pixels or device pixels. Device-pixel output improves text legibility but changes coordinate math. For responsive QA, run the same script at each target viewport and keep the browser version and rendering environment fixed.

2. Automate screenshots with Playwright

Install Playwright in your project, then launch a browser, open the page, and call page.screenshot(). The Page API supports a path and fullPage: true; the screenshot tooling also supports element captures, image type selection, and high-resolution output.

npm install -D playwright
npx playwright install

Viewport, element, and full-page captures

const { chromium } = require('playwright');

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

  // The visible browser viewport.
  await page.screenshot({ path: 'viewport.png', type: 'png' });

  // A specific element.
  const header = page.locator('header');
  await header.screenshot({ path: 'header.webp', type: 'webp' });

  // The complete scrollable document.
  await page.screenshot({ path: 'full-page.jpeg', type: 'jpeg' });
  await page.screenshot({ path: 'full-page-explicit.png', fullPage: true });

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

Replace the URL and selector with the page and component you need. Wait for a meaningful page state before capturing; a navigation event alone does not guarantee that images or application data have rendered.

Reusable capture script

const { chromium } = require('playwright');

async function capture(url, output, options = {}) {
  const browser = await chromium.launch();
  try {
    const page = await browser.newPage({
      viewport: options.viewport || { width: 1440, height: 900 },
      deviceScaleFactor: options.deviceScaleFactor || 1
    });
    await page.goto(url, { waitUntil: options.waitUntil || 'networkidle' });
    if (options.waitForSelector) await page.locator(options.waitForSelector).waitFor();
    if (options.delayMs) await page.waitForTimeout(options.delayMs);
    await page.screenshot({
      path: output,
      fullPage: Boolean(options.fullPage),
      type: options.type || 'png'
    });
  } finally {
    await browser.close();
  }
}

capture('https://example.com', 'site.png', {
  fullPage: true,
  type: 'png',
  waitForSelector: 'main'
});

For a single element, call locator.screenshot() instead of page.screenshot(). Keep filenames explicit so CI artifacts and review links are predictable.

3. Use the Playwright CLI from a shell

The CLI is useful for repeatable shell workflows and quick investigations. It exposes commands for viewport screenshots, selected elements, custom filenames, full-page capture, image type, and high-resolution device-pixel output. Run npx playwright --help in the installed version to see the exact command syntax for that release, then commit the command in a script.

# Inspect the available screenshot commands and flags
npx playwright --help

# A typical scripted invocation (check --help for your installed version)
npx playwright screenshot --help

CLI flags change between releases, so use the help output from the version pinned in your project rather than copying an unpinned command into CI.

4. Use Puppeteer when your project is already JavaScript based

Puppeteer is a JavaScript library for automating Chrome and Firefox through the Chrome DevTools Protocol and WebDriver BiDi. It supports full-page and element visual snapshots. Choose it when your existing automation, fixtures, or browser lifecycle already use Puppeteer.

npm install puppeteer
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  try {
    const page = await browser.newPage();
    await page.setViewport({ width: 1440, height: 900 });
    await page.goto('https://example.com', { waitUntil: 'networkidle0' });

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

    const element = await page.$('header');
    if (!element) throw new Error('header was not found');
    await element.screenshot({ path: 'header.png' });
  } finally {
    await browser.close();
  }
})();

5. Take a one-off screenshot with browser DevTools

  1. Open the page in your browser and open DevTools.
  2. Use the element inspector to select a component, or open the command menu and search for a screenshot action.
  3. Choose a viewport or full-page capture and save the file.

DevTools is appropriate for a bug report or design review. It is less suitable for CI because the result depends on manual state, browser settings, and the machine that performed the capture.

6. Build visual regression checks with Playwright Test

Playwright Test’s toHaveScreenshot() creates reference images and compares later runs against them.

import { test, expect } from '@playwright/test';

test('home page remains stable', async ({ page }) => {
  await page.goto('https://example.com', { waitUntil: 'networkidle' });
  await expect(page).toHaveScreenshot('home.png', { fullPage: true });
});

Commit reference images deliberately. Review every diff before updating a baseline. Operating system, browser version, browser settings, hardware, power source, and headless mode can change rendering, so capture and comparison jobs should use the same environment.

7. Make captures stable across responsive and lazy-loaded pages

  • Responsive checks: run one capture per target viewport and record the viewport dimensions with the artifact.
  • Lazy content: wait for the relevant selector or application state before saving a full-page image; otherwise below-the-fold content may be absent.
  • Animations: disable or finish transitions in the test environment so two captures do not differ only by timing.
  • Fonts and assets: wait until the page has loaded the assets that affect layout, then capture.
  • Coordinates: use CSS-pixel coordinates for layout logic and device-pixel output only when the consuming workflow expects it.

8. Troubleshooting common screenshot failures

Symptom Likely cause Fix
Blank or partially rendered image Capture ran before application content or lazy images loaded. Wait for a selector, a known application-ready state, or a controlled delay.
Full-page image cuts off content The page was captured as a viewport or content changed while scrolling. Use full-page capture and make the page state deterministic before the call.
Element screenshot throws The selector matches nothing or the element is not visible. Check the selector, wait for it, and fail with a useful error when it is absent.
Visual diff on every CI run Different browser, OS, hardware, headless mode, fonts, or power conditions. Pin the browser and run baseline and comparison jobs in the same environment.
Text appears at the wrong scale Device-pixel scaling differs from the CSS viewport. Set the device scale deliberately and keep coordinate systems consistent.
Navigation timeout The site is slow, blocked, or never reaches the chosen load condition. Check the URL and network access, then choose a readiness condition that matches the application.
Intermittent differences Animations, rotating content, ads, timestamps, or random data. Freeze dynamic inputs or hide them in the test environment before capture.

9. Performance, reliability, and cost decisions

Local browsers

Local Playwright and Puppeteer give maximum control and avoid a per-image service charge, but your team owns browser installation, updates, fonts, concurrency, sandboxing, storage, and CI debugging. Reuse a browser process for a batch and create pages per URL when your workflow allows it.

Hosted capture

A hosted API is useful when you need a stable capture endpoint, bulk jobs, signed delivery, or no browser runtime in your application. Check response status and save the returned bytes; retry only failures that are safe to repeat. Cache unchanged URLs when freshness permits.

Visual-regression cost

Store only the baselines and artifacts you need, and review diffs before accepting them. A high device-pixel scale increases image size and review time, so reserve it for cases where legibility matters.

10. Or skip the browser setup with ScreenshotNeo

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 like a visitor, then removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and the response identifies the result with X-Page-Verdict and X-Billed headers.

See the complete option list and request details in the ScreenshotNeo documentation. Options include full-page capture with lazy images loaded, CSS-selector element capture, dark mode, 12 device presets or any viewport, retina scale, PDF paper size and margins, landscape and page ranges, HTML/CSS to image, custom CSS and JavaScript, pre-capture clicks, hidden selectors, waits for a selector or delay or network idle, blocking ads, trackers, requests, or resource types, custom headers, cookies, user agent and Authorization, timezone and geolocation, transparent backgrounds, image resizing, configurable-TTL caching, signed links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification.

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

ScreenshotNeo also provides an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots, and every feature is included on every plan.

Create a free ScreenshotNeo account and get 1,000 screenshots each month with no card.

11. FAQ

Is Playwright or Puppeteer better for screenshots?

Use Playwright for a new, general screenshot and visual-regression workflow. Puppeteer is a sound choice when the project already depends on its JavaScript browser automation API.

What is the most reliable full-page method?

Use a pinned Playwright or Puppeteer browser, wait for the page’s real ready state, then call the full-page screenshot method. Keep the capture environment identical to the comparison environment.

Should visual regression use PNG or JPEG?

Use the lossless format your review process expects for pixel comparisons. Choose JPEG when smaller photographic files matter more than exact pixel fidelity.

When should I use an API instead of running Chromium?

Use an API when browser maintenance, distributed jobs, cleanup of consent UI, or AI-agent access would otherwise become application work.

Can I capture only one component?

Yes. Playwright and Puppeteer can capture a selected element, and ScreenshotNeo accepts a CSS selector for element capture.