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

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

For hundreds of independent URLs, use a bounded worker queue: launch one browser, run a small fixed number of screenshot jobs at a time, save a result or error for every URL, and continue when individual pages fail. Tune the number of workers on your own pages and machine; Playwright does not publish a universal concurrency setting or guaranteed throughput for arbitrary screenshot batches.

Build a bounded Playwright screenshot queue

A custom Node.js script is a straightforward fit when you have a URL list and want a predictable output directory. The example below reads one URL per line from urls.txt, opens a separate browser context for each job to prevent cookies and local storage from leaking between URLs, and limits how many jobs run at once. It writes a JSONL manifest with a result for each input line.

Install Playwright and prepare the input

  1. Install Node.js and create a project directory.
  2. From that directory, run npm init -y and npm install playwright.
  3. Install the Chromium browser used by Playwright with npx playwright install chromium.
  4. Create urls.txt with one absolute HTTP or HTTPS URL per line. Blank lines and lines beginning with # are ignored.

Runnable batch script

Save this as bulk-screenshot.mjs. It captures the viewport by default; set FULL_PAGE=true in the environment to capture the full scrollable page. Set WORKERS to a positive integer to change the concurrency limit.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import { chromium } from 'playwright';
import { createHash } from 'node:crypto';
import { mkdir, readFile, appendFile } from 'node:fs/promises';
import path from 'node:path';

const inputPath = process.argv[2] ?? 'urls.txt';
const outputDir = process.argv[3] ?? 'screenshots';
const workers = Number.parseInt(process.env.WORKERS ?? '4', 10);
const fullPage = process.env.FULL_PAGE === 'true';
const timeoutMs = Number.parseInt(process.env.TIMEOUT_MS ?? '30000', 10);

if (!Number.isInteger(workers) || workers < 1) {
  throw new Error('WORKERS must be a positive integer');
}
if (!Number.isInteger(timeoutMs) || timeoutMs < 1) {
  throw new Error('TIMEOUT_MS must be a positive integer');
}

const lines = (await readFile(inputPath, 'utf8')).split(/r?n/);
const jobs = lines
  .map((line, index) => ({ line: line.trim(), inputLine: index + 1 }))
  .filter(({ line }) => line && !line.startsWith('#'))
  .map(({ line, inputLine }) => {
    let url;
    try {
      url = new URL(line);
      if (!['http:', 'https:'].includes(url.protocol)) throw new Error('unsupported protocol');
    } catch (error) {
      return { input: line, inputLine, invalid: error.message };
    }
    const id = createHash('sha256').update(line).digest('hex').slice(0, 16);
    return { input: line, inputLine, url: url.href, id };
  });

await mkdir(outputDir, { recursive: true });
const manifestPath = path.join(outputDir, 'results.jsonl');
const browser = await chromium.launch();
let nextIndex = 0;

async function record(result) {
  await appendFile(manifestPath, `${JSON.stringify(result)}n`);
}

async function capture(job) {
  if (job.invalid) {
    await record({ input: job.input, inputLine: job.inputLine, status: 'invalid', error: job.invalid });
    return;
  }
  let context;
  try {
    context = await browser.newContext();
    const page = await context.newPage();
    page.setDefaultNavigationTimeout(timeoutMs);
    page.setDefaultTimeout(timeoutMs);
    const response = await page.goto(job.url, { waitUntil: 'domcontentloaded', timeout: timeoutMs });
    const outputPath = path.join(outputDir, `${job.id}.png`);
    await page.screenshot({ path: outputPath, fullPage });
    await record({
      input: job.input,
      inputLine: job.inputLine,
      status: 'ok',
      outputPath,
      httpStatus: response?.status() ?? null,
      fullPage
    });
  } catch (error) {
    await record({ input: job.input, inputLine: job.inputLine, status: 'error', error: String(error) });
  } finally {
    await context?.close().catch(() => {});
  }
}

async function worker() {
  while (true) {
    const index = nextIndex++;
    if (index >= jobs.length) return;
    await capture(jobs[index]);
  }
}

try {
  await Promise.all(Array.from({ length: Math.min(workers, jobs.length) }, () => worker()));
} finally {
  await browser.close();
}
console.log(`Processed ${jobs.length} input(s). Results: ${manifestPath}`);

Run it with node bulk-screenshot.mjs urls.txt screenshots. To request full-page images, use FULL_PAGE=true node bulk-screenshot.mjs. On Windows PowerShell, set the option first with $env:FULL_PAGE="true", then run the Node command. The script names files with a short hash rather than a URL-derived filename, avoiding path characters and collisions from simple filename sanitization; the manifest preserves the mapping to each original input.

#1 Best Overall
Lavsoul 4K Webcam with Microphone for PC & Streaming Computer Camera
  • ULTRA HD 4K CLARITY: Stand out in every video call with breathtaking 4K video at 30fps or smooth 1080p at 60fps. Powered by a premium 1/2.5" CMOS sensor and a wide f/1.78 aperture, this webcam captures every detail with vibrant color and stunning low-light performance-so you always look your best
  • FAST AUTOFOCUS & SMART LIGHT CORRECTION: No more blurry moments with this webcam for PC. Advanced Phase Detection Auto Focus (PDAF) locks onto your face instantly and keeps you sharp-even when you move. Built-in light correction adapts to your environment, balancing brightness and contrast for a flawless image in dim rooms or bright spaces
  • DUAL NOISE-CANCELING MICS: Speak with confidence using this webcam with microphones. Dual microphones with intelligent noise-canceling tech isolate your voice and reduce background noise-suitable for webinars, live streams, team meetings, and virtual interviews
  • WIDE-ANGLE LENS & FLEXIBLE MOUNTING OPTIONS: Capture more of your world with an 80 field of view and full 360 swivel rotation. Whether this streaming webcam is mounted on a laptop, monitor, or tripod, it allows you to find the right angle for any setup
  • BUILT-IN PRIVACY COVER & PLUG-AND-PLAY SIMPLICITY: Protect your privacy with a secure sliding lens cover that blocks the camera when not in use. Setup is a breeze-just plug into any USB-A port and start streaming, chatting, or recording instantly. The USB webcam is compatible with Zoom, Microsoft Teams, Skype, OBS Studio, and all major platforms across Windows, macOS, and Linux

Choose concurrency based on the actual batch

The queue keeps the number of active jobs bounded, but there is no single best worker count. Page size and complexity, remote-server response times, screenshot dimensions, readiness waits, and the machine’s CPU and memory all affect runtime. Start with a modest value, run a representative subset, and increase it only while the machine remains stable and target sites continue to respond appropriately.

  • More workers: may overlap navigation and capture work, but use more memory and CPU and can increase load on target sites.
  • Fewer workers: reduce simultaneous resource use and can make ordering easier to reason about, at the cost of less parallel execution.
  • One worker: use WORKERS=1 when you need serialized jobs or have a target site or environment that does not tolerate parallel requests.

Playwright Test also offers worker controls if each URL is modeled as a test. Its workers are separate OS processes, each launching its own browser, so a test-runner worker is not equivalent in overhead to opening another page in a single browser process. The official examples include npx playwright test --workers 4 and a configuration using workers: process.env.CI ? 2 : undefined; the appropriate value depends on the workload and environment. See Playwright Test parallelism.

Wait for the right page state before capture

The example waits for domcontentloaded, which is a bounded general starting point, not proof that every site has finished rendering its useful content. For known sites, wait for a meaningful selector or application state before taking the screenshot. Playwright supports navigation wait conditions including commit, domcontentloaded, load (the default), and networkidle. The Page API marks networkidle as discouraged for testing and recommends using web assertions to assess readiness instead: Page API reference.

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

For a known page with a stable content marker, add an explicit wait after navigation, for example await page.locator('main article').waitFor({ state: 'visible', timeout: timeoutMs });. For a mixed list, make the readiness rule configurable by site or use a bounded delay only when a fixed delay is appropriate. Avoid an unbounded wait: one page that never reaches the expected state should not hold up the batch indefinitely.

Rank #2
10.1 Inch Mini Netbook, Quad-Core Processor Laptop Computer, 2GB Memory 64GB Storage Android 12 Portable Notebook Built-in Webcam, WiFi & Bluetooth Keyboard & Mouse for Home Schooling & Office Work
  • 【Efficient Quad-Core Performance】 Powered by a 1.8GHz Quad-Core processor, this mini laptop ensures smooth multitasking. With 2GB RAM and 64GB ROM (expandable to 1TB), it handles daily work and online tasks with ease.
  • 【10.1" HD IPS Display & GMS Support】 Featuring a 1280x800 HD IPS screen, this cheap laptop delivers vibrant visuals. Pre-installed with Android OS and GMS, you get direct access to the Google Play Store for apps.
  • 【Ultra-Portable & Lightweight Design】 Weighing only 1.76 lbs, this Blue computer is designed for mobility. Its compact form makes it an ideal companion for students and professionals for home schooling or trips.
  • 【Versatile Connectivity Options】 Stay productive with dual USB 2.0 ports, a headphone jack, and a TF card slot. This computer for kids and adults features built-in Wi-Fi and Bluetooth for stable connections.
  • 【Complete All-in-One Bundle】 This kid laptop kit includes the laptop, carrying bag, mouse, mouse pad, and power adapter. It is the perfect ready-to-use set for online classes, remote work, and entertainment.

Choose viewport, full-page, and output settings

Viewport or full-page

page.screenshot() captures the current viewport unless configured otherwise. Set fullPage: true to capture the full scrollable document; the resulting files can be substantially larger. Playwright also supports capturing a locator’s element, which is useful when the artifact should contain a particular component rather than an entire page. See Playwright screenshots.

Format, quality, and pixel scale

Playwright can save a screenshot to a path or return image bytes for post-processing. PNG is the default; JPEG and WebP can be selected, with quality available for lossy formats. CSS scale produces one image pixel per CSS pixel, while device scale uses device pixels and may produce a larger image. Select format and scale to match the downstream use: visual inspection may favor fidelity, while large archives or transfers may favor smaller files. Check the options available in the installed version’s Page API.

Element capture and dynamic content

For an element screenshot, locate the target and call its screenshot method, such as await page.locator('.report').screenshot({ path: outputPath });. For repeatable comparisons, keep the browser version, operating system, headless mode, hardware environment, and screenshot settings consistent. Playwright notes that rendering can vary with these factors; masking or hiding dynamic content is appropriate only if it does not remove information the screenshot is meant to show. See Visual comparisons.

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.

Keep the batch recoverable and results interpretable

The script records one JSON object per processed input in results.jsonl. Successful records include the screenshot path and response status when a navigation response was available; errors include the failure message. Use this manifest to identify failed URLs and retry only those that are plausibly transient rather than repeating the entire batch.

Rank #3
Sale
Logitech C920x HD Pro Webcam, Full HD 1080p/30fps - Black w/Blue Yeti USB Microphone - Blackout
  • Webcam comes with a 3-month XSplit VCam license and no privacy shutter. XSplit VCam lets you remove, replace and blur your background without a Green Screen.
  • Full HD 1080p video calling and recording at 30 fps - You’ll make a strong impression when it counts with crisp, clearly detailed and vibrantly colored video.
  • Stereo audio with dual mics - Capture natural sound on calls and recorded videos.
  • Custom three-capsule array: This professional USB mic produces clear, powerful, broadcast-quality sound for YouTube videos, Twitch game streaming, podcasting, Zoom meetings, music recording and more
  • Blue VOICE software: Elevate your streamings and recordings with clear broadcast vocal sound and entertain your audience with enhanced effects, advanced modulation and HD audio samples

For a rerun, decide whether you want to append to the existing manifest or start a fresh run: this example appends, so move or remove the old manifest before a clean run. Do not use a shared output filename for concurrent jobs. The hash-based filename maps identical input strings to the same name; if the same URL appears more than once and each occurrence must produce a distinct artifact, include the input line number in the filename and manifest.

Custom queue or Playwright Test?

Pattern Best fit Concurrency and isolation Trade-off
Custom Node queue A URL file or data feed, custom output naming, and a manifest tailored to the batch. Set a bounded job count directly; use pages or contexts according to whether jobs may share browser state. You own input validation, status records, retries, and recovery.
Playwright Test Each URL is naturally an independent test and the team wants test-runner reporting. Configure workers; by default, test files run in parallel while tests in one file run in order. Fully parallel modes are available. Workers are separate processes with their own browsers. Worker processes have more overhead than simply adding pages to one browser, and shared filenames or mutable state need care.

These are both viable patterns, not a universal speed ranking. The choice depends on input handling, the amount of isolation needed, resource overhead, failure reporting, determinism, and whether test-runner reporting is useful. See Pages and contexts and parallel execution.

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

Troubleshoot common batch failures

  • Browser executable missing: install the browser for the Playwright package with npx playwright install chromium.
  • Navigation timeout: the server may be slow or unreachable, or the chosen wait condition may not occur. Check the URL, use a page-appropriate readiness condition, and set a finite timeout that matches the workload.
  • Screenshot is blank or incomplete: navigation completion may precede client-side content rendering. Wait for a meaningful selector or application state; verify whether the requested artifact is viewport or full-page.
  • Output files overwrite one another: ensure each job has a unique output name. The example uses a hash of the URL; add an occurrence identifier if duplicate URL entries need separate files.
  • Memory pressure or browser instability: lower WORKERS, especially for long full-page captures or resource-heavy pages, and test changes on a representative subset.
  • Inconsistent visual output: standardize browser, OS, headless mode, device scale, and other settings. Rendering can differ between environments, so do not assume pixel-identical output across machines.

Or skip the browser setup

If you would rather send screenshot jobs to an API, ScreenshotNeo accepts a URL in one GET request and returns an image or PDF. Its API accepts other screenshot APIs’ parameter names too. The following cURL example saves a WebP screenshot; API details and options are in the ScreenshotNeo documentation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

ScreenshotNeo removes cookie and consent banners, newsletter popups, and chat widgets before capture; those cleanup steps can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and each response includes X-Page-Verdict and X-Billed headers. It also provides an MCP server with take_screenshot, get_page_info, and capture_pdf tools for AI agents. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots.

Sign up for ScreenshotNeo’s free plan: 1,000 screenshots a month, no card required.

Rank #4
Webcam Cover for Logitech C920 C930e c922x Lens Privacy Shutter Slider
  • Compatible with Logitech C920x HD Pro Webcam, Full HD 1080p/30fps Video Calling. Compatible with Logitech C920 Hd Pro Webcam. Compatible with Logitech HD Pro Webcam C920 Widescreen Video Calling and Recording Webcam.
  • Compatible with Logitech C930e Webcam. Compatible with Logitech C922 Pro Stream Webcam 1080P Camera for HD Video Streaming. Compatible with Logitech Privacy Cover for C920 and C930e.
  • This webcam cover conveniently blocks your camera cover to protect your privacy.
  • This also compatible with other popular webcams. This is also known as webcam lid, webcam cap, webcam protector, web camera privacy cover.
  • ienza is a registered trademark and a registered Amazon brand. Use of the ienza trademark without the prior written consent of ienza, LLC. may constitute trademark infringement and unfair competition in violation of federal and state laws. ienza products are developed as cost-effective alternatives to OEM parts. They are not necessarily endorsed by the OEMs

Cost, runtime, and version considerations

A local Playwright batch has no per-screenshot API charge, but it consumes your machine’s compute, memory, storage, and network capacity, and it depends on target-site response times. There is no supported universal URLs-per-second estimate for arbitrary pages. Measure a representative batch on the machine and network you intend to use, including the size of full-page output and the readiness waits you actually need.

Playwright API details can vary by release. Confirm screenshot and context options against the documentation matching your installed package before relying on release-specific behavior; the release notes provide version context.

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.

Frequently Asked Questions

Can the script read a CSV or database instead of a text file?

Yes. Keep the queue and capture function, and replace the input parsing with a reader for your data source. Preserve a stable input identifier in each manifest record so results can be joined back to the original data.

Can screenshots be returned as bytes rather than written to disk?

Yes. Playwright screenshot calls can return image bytes when no output path is supplied; send those bytes to the storage or processing step your application needs.

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.