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

Store each page as a capture record with its URL, its own readiness rule, and a unique output path. Then loop through the records in Playwright: navigate using the chosen event, wait for any page-specific selector, save the screenshot, and handle errors per URL so one timeout does not stop the batch.

Choose a wait condition for each URL

Navigation events signal different stages of loading, so choose the least restrictive condition that reliably means the content you need is ready.

  • commit: the response has been received and document loading has started. Use it only when an early capture is acceptable.
  • domcontentloaded: the document’s DOM content has loaded. This can suit pages whose relevant content is rendered with the initial document.
  • load: waits for the page load event, which includes dependent resources such as images and stylesheets.
  • A selector: wait for a meaningful element when a page renders the needed content asynchronously, such as a chart or application panel.
  • A fixed delay: use only when no reliable observable signal exists. It is a heuristic: it may be too short on a slow run and waste time on a fast one.

Playwright defines networkidle as no network connections for at least 500 ms. Its Page API discourages using that condition for tests and recommends assessing readiness with web assertions instead. Pages with polling, analytics, or other continuing requests can also make network idleness a poor proxy for visible readiness. Prefer a selector or another application-specific condition when possible. Playwright Page API and load-state documentation describe these options.

Set up a per-URL capture list

JSON works well for a small script; CSV is also suitable if you parse its rows into the same record shape. Include only the wait fields relevant to each page. A useful record can contain:

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.
  • url: the page to capture.
  • waitUntil: a navigation event such as domcontentloaded or load.
  • waitFor: an optional selector that identifies required page content.
  • output: a unique image filename.

Keep output names unique. A stable index combined with a sanitized hostname is one straightforward approach; without unique names, later captures can overwrite earlier ones. The loop, naming scheme, and error report below are orchestration choices built around Playwright’s documented browser primitives.

Run the bulk capture with Playwright

The following JavaScript example uses Playwright’s library API, launches one browser for the batch, opens a fresh page for each record, and continues after an individual capture fails. It creates the output directory and writes a JSON-lines report: each line records either a successful file or the URL and error for a failed capture.

Install the package and browser first:

npm init -y
npm install playwright
npx playwright install chromium

Save this as bulk-screenshots.mjs and run it with node bulk-screenshots.mjs:

Rank #2
Free Fling File Transfer Software for Windows [PC Download]
  • Intuitive interface of a conventional FTP client
  • Easy and Reliable FTP Site Maintenance.
  • FTP Automation and Synchronization
import { chromium } from 'playwright';
import { mkdir, writeFile } from 'node:fs/promises';

const captures = [
  {
    url: 'https://example.com/',
    waitUntil: 'domcontentloaded',
    output: 'screenshots/001-example-com.png',
  },
  {
    url: 'https://example.org/app',
    waitUntil: 'domcontentloaded',
    waitFor: '[data-ready="true"]',
    output: 'screenshots/002-example-org.png',
  },
];

const timeout = 30_000;
const results = [];

await mkdir('screenshots', { recursive: true });
const browser = await chromium.launch();

try {
  for (const item of captures) {
    const page = await browser.newPage();
    try {
      await page.goto(item.url, {
        waitUntil: item.waitUntil ?? 'load',
        timeout,
      });

      if (item.waitFor) {
        await page.locator(item.waitFor).waitFor({
          state: 'visible',
          timeout,
        });
      }

      await page.screenshot({ path: item.output, fullPage: true });
      results.push({ url: item.url, status: 'ok', output: item.output });
    } catch (error) {
      results.push({
        url: item.url,
        status: 'error',
        error: error instanceof Error ? error.message : String(error),
      });
    } finally {
      await page.close();
    }
  }
} finally {
  await browser.close();
}

await writeFile(
  'screenshots/report.jsonl',
  results.map((result) => JSON.stringify(result)).join('n') + 'n',
);
console.log(results);

Replace the example URLs, selectors, and output paths with your own. For pages whose relevant content is already present in the initial document, set waitUntil to domcontentloaded. For a page that needs its application panel, keep a suitable navigation event and set waitFor to a selector that appears only when that panel is ready. The sample uses a finite 30-second timeout for both navigation and selector waiting; adjust it to your pages and capture requirements.

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

fullPage: true captures the full scrollable page; use false or omit the option for a viewport screenshot. Playwright’s Page API documents navigation and screenshot options, including timeouts. See the Page API.

Make a batch reliable and visually consistent

Continue past failures

Catch errors inside the per-URL loop, as in the example. This preserves successful files if one site times out or a selector never appears. Keep the URL and error in the report, then retry only failed entries rather than recapturing the entire batch.

Keep the rendering environment stable

For visual comparisons, use a consistent browser, operating environment, fonts, settings, and headless configuration. Rendering can vary with the platform, hardware, power state, and browser setup. Playwright’s visual comparison guidance describes these sources of variation. Visual comparisons and snapshots

Control animation and changing content

Animations, rotating banners, timestamps, and live data can make otherwise identical captures differ. If the goal is repeatable visual regression, consider disabling animations or masking volatile elements. Playwright’s screenshot assertion options include animation handling, and its guidance explains screenshot comparison behavior. A visually stable screenshot is not by itself proof that the page is semantically ready; keep the readiness condition tied to the content you need. Playwright snapshot guidance

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

Use a configuration-driven CLI instead

If you would rather describe captures in configuration than write your own loop, shot-scraper documents URL entries and selector-based waiting. That can make per-page readiness rules easy to express, while a custom Playwright script gives you direct control over output naming, reporting, viewport, and browser context. The available documentation supports these workflows but does not establish a universal performance winner. Check the tool’s current documentation for exact configuration syntax and options before building a batch around it. shot-scraper documentation

Troubleshoot common bulk-capture failures

A page times out during navigation

The selected navigation event may not fire before the timeout, or the site may be slow or unavailable. Confirm the URL opens from the capture environment, choose the least restrictive event that still suits the content, and keep the finite timeout. The per-URL catch records the failure without discarding other screenshots.

A selector wait times out

Check that the selector exists on that URL and becomes visible in the intended state. It may be incorrect, hidden, or absent because the application failed to render. Test the selector on the page, and use a condition tied to the actual content rather than a generic loading indicator where possible.

The screenshot is blank or missing expected content

The navigation event may have completed before client-side content appeared. Add a selector wait for that content, or choose a more appropriate navigation event. Do not treat networkidle as a universal readiness fix; Playwright cautions against relying on it for tests.

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

One output replaces another

Give every record a distinct output path. A stable index and sanitized hostname help keep names readable and prevent collisions.

Images differ between runs

Check for animation and volatile page elements, then compare captures using the same browser and operating environment. Differences can also come from fonts, platform, settings, hardware, power state, or headless mode.

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

Or skip the browser setup

For a hosted one-request option, ScreenshotNeo is a website screenshot API and MCP server. A single request captures one URL; for a list with different readiness requirements, send a separate request per URL and use the relevant wait option for each. Check the ScreenshotNeo documentation for the current parameters and response details.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
  • Cookie and consent banners are accepted like a visitor, and 60+ known consent platforms, newsletter popups, and chat widgets are removed before capture; each step can be turned off.
  • Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing; response headers report the page verdict and whether the request was billed.
  • An 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 screenshots; yearly billing gives two months free, and every feature is available on every plan.

Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.

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

Frequently Asked Questions

Can different URLs use different selectors in the same batch?

Yes. Give each capture record its own optional selector and wait only for the pages that need one.

Should I create a new page for every URL?

The example creates and closes a page per capture to isolate pages. You can reuse pages carefully, but reset state that could leak between URLs.

Does waiting for a selector guarantee identical screenshots?

No. It confirms a page condition, but animation, live content, fonts, browser, and operating environment can still change rendering.

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.

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.