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

Use a browser automation script to read the URL list, visit each page, capture a screenshot, and save it under a unique filename. The example below uses Playwright with Node.js and records a result for every URL, including failures. Choose a normal viewport capture for compact preview cards; use full-page capture when you need the entire scrollable page.

What you need to make thumbnails in a batch

A list of URLs alone is not a batch job: your script must loop over the list and decide how to name files, handle errors, and limit simultaneous browser work. Playwright’s browser Page API supplies the building blocks—navigate, capture, and close—while the list processing and output manifest are yours to implement.

  • Node.js installed on the machine that will run the job.
  • A plain text file containing one URL per line.
  • Enough disk space for the resulting images.

The workflow below uses Chromium through Playwright. Its concurrency value is an adjustable starting point, not a universal safe limit; pages vary in load time and resource use.

Install Playwright and prepare your URL list

  1. Create a project: run mkdir site-thumbnails, then cd site-thumbnails.
  2. Initialize Node.js and install Playwright: run npm init -y, then npm install playwright.
  3. Install the browser: run npx playwright install chromium.
  4. Create urls.txt: put one address on each line, for example https://example.com. Blank lines and lines beginning with # are ignored by the script.

The script adds https:// to a line that has no scheme. That is convenient for ordinary website hostnames, but only use it when HTTPS is the intended destination. It rejects schemes other than HTTP and HTTPS.

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.
#1 Best Overall
Sale
Philips 24 Inch Computer Monitor FHD 100Hz VA VESA Flicker-Free, 241V8LB
  • CRISP CLARITY: This 23.8″ Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
  • INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
  • THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors
  • WORK SEAMLESSLY: This sleek monitor is virtually bezel-free on three sides, so the screen looks even bigger for the viewer. This minimalistic design also allows for seamless multi-monitor setups that enhance your workflow and boost productivity
  • A BETTER READING EXPERIENCE: For busy office workers, EasyRead mode provides a more paper-like experience for when viewing lengthy documents

Run this Node.js batch screenshot script

Save the following as thumbnails.mjs next to urls.txt. It reuses one browser, processes a bounded number of pages at a time, saves viewport screenshots as WebP, and writes a JSON manifest with each original URL, output filename, and outcome.

import { chromium } from 'playwright';
import { createHash } from 'node:crypto';
import { mkdir, readFile, writeFile } from 'node:fs/promises';
import path from 'node:path';

const inputFile = process.argv[2] ?? 'urls.txt';
const outputDir = process.argv[3] ?? 'thumbnails';
const concurrency = Math.max(1, Number(process.env.CONCURRENCY) || 3);
const navigationTimeoutMs = 30_000;

function normalizeUrl(line) {
  const value = line.trim();
  if (!value || value.startsWith('#')) return null;
  const candidate = /^[a-z][a-zd+.-]*:///i.test(value)
    ? value
    : `https://${value}`;
  const url = new URL(candidate);
  if (!['http:', 'https:'].includes(url.protocol)) {
    throw new Error(`Unsupported URL scheme: ${url.protocol}`);
  }
  return url;
}

function outputName(url, rowNumber) {
  const host = url.hostname.replace(/[^a-z0-9.-]/gi, '_');
  const pathPart = url.pathname.replace(/[^a-z0-9._-]+/gi, '_').slice(0, 48) || 'home';
  const hash = createHash('sha256').update(url.href).digest('hex').slice(0, 10);
  return `${String(rowNumber).padStart(4, '0')}-${host}-${pathPart}-${hash}.webp`;
}

const lines = (await readFile(inputFile, 'utf8')).split(/r?n/);
const entries = [];
for (let i = 0; i < lines.length; i++) {
  try {
    const url = normalizeUrl(lines[i]);
    if (url) entries.push({ rowNumber: i + 1, original: lines[i].trim(), url });
  } catch (error) {
    entries.push({ rowNumber: i + 1, original: lines[i].trim(), inputError: error.message });
  }
}

await mkdir(outputDir, { recursive: true });
const browser = await chromium.launch({ headless: true });
const results = new Array(entries.length);
let nextIndex = 0;

async function worker() {
  while (true) {
    const index = nextIndex++;
    if (index >= entries.length) return;
    const entry = entries[index];

    if (entry.inputError) {
      results[index] = { row: entry.rowNumber, url: entry.original, status: 'invalid_url', error: entry.inputError };
      continue;
    }

    const filename = outputName(entry.url, entry.rowNumber);
    const file = path.join(outputDir, filename);
    const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
    try {
      const response = await page.goto(entry.url.href, {
        waitUntil: 'domcontentloaded',
        timeout: navigationTimeoutMs,
      });
      await page.screenshot({ path: file, type: 'webp', quality: 80 });
      results[index] = {
        row: entry.rowNumber,
        url: entry.original,
        finalUrl: page.url(),
        status: 'captured',
        httpStatus: response?.status() ?? null,
        file: filename,
      };
    } catch (error) {
      results[index] = {
        row: entry.rowNumber,
        url: entry.original,
        status: 'failed',
        error: error.message,
      };
    } finally {
      await page.close().catch(() => {});
    }
  }
}

try {
  await Promise.all(Array.from({ length: Math.min(concurrency, entries.length || 1) }, () => worker()));
} finally {
  await browser.close();
}

await writeFile(path.join(outputDir, 'manifest.json'), JSON.stringify(results, null, 2));
const captured = results.filter((result) => result?.status === 'captured').length;
console.log(`Captured ${captured} of ${entries.length} entries. See ${path.join(outputDir, 'manifest.json')}.`);

Run it with node thumbnails.mjs. To use different input and output paths, run node thumbnails.mjs urls.txt output-images. Set a smaller or larger worker count for the job with, for example, CONCURRENCY=2 node thumbnails.mjs.

What the script saves

Each successful capture is a WebP file in the output directory. Its name combines the input row, hostname, a shortened sanitized path, and a URL hash. The hash helps distinguish URLs that would otherwise map to the same readable name; the row number also keeps repeated input rows distinct. manifest.json preserves the input URL, final URL after redirects for successful captures, HTTP status when available, filename, and outcome.

Rank #2
Philips 22 Inch Computer Monitor FHD 100Hz VA VESA Flicker-Free, 221V8LB
  • CRISP CLARITY: This 22 inch class (21.5″ viewable) Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
  • 100HZ FAST REFRESH RATE: 100Hz brings your favorite movies and video games to life. Stream, binge, and play effortlessly
  • SMOOTH ACTION WITH ADAPTIVE-SYNC: Adaptive-Sync technology ensures fluid action sequences and rapid response time. Every frame will be rendered smoothly with crystal clarity and without stutter
  • INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
  • THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors

A navigation can return an HTTP error response and still render a page; the script records the response status but captures what the browser displayed. A thrown navigation or screenshot error is recorded as failed, and the worker continues with the rest of the list.

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

Choose viewport or full-page capture

Viewport thumbnail

The example captures the initial 1280-by-800 CSS-pixel viewport. This usually works better for a grid of small preview cards because the images have consistent dimensions. The actual output pixel dimensions can also depend on screenshot scale and device settings.

Full-page image

To capture the full scrollable document, add fullPage: true to the page.screenshot options. Playwright describes a full-page screenshot as an image of the entire scrollable page, as if it were a very tall screen. Long pages can therefore produce extremely tall files rather than compact thumbnails.

Rank #3
Sale
Dell 24 Monitor - SE2426H - 23.8-inch FHD (1920x1080) 144Hz 1ms Display, in-Plane Switching (IPS) Technology, AMD FreeSync™, TÜV 3-Star 2X HDMI, Tilt
  • Clear visuals. Fluid motion: A 144Hz refresh rate and 1ms MPRT deliver smooth, tear‑free motion across work, gaming, and streaming for clearer, more fluid viewing.
  • Eye comfort: TÜV Rheinland 3‑star* certification reduces harmful blue light while preserving stunning color quality without compromise. *TÜV Rheinland 3-star eye comfort certification.
  • Wide viewing angle: Get consistent views across a wide 178° /178° viewing angle.
  • In-Plane Switching (IPS): See excellent color accuracy and consistency across wide viewing angles with In-plane Switching (IPS) technology.
  • Ultra-thin bezels: Maximize your viewing experience with thin bezels.

Element capture or post-processing

For a specific card or page region, locate it and call locator.screenshot({ path: file }) instead of taking a page screenshot. Playwright can also return screenshot bytes rather than writing directly to a file; that is useful if your next step is image processing or storage. If the downstream interface requires exact thumbnail dimensions, resize or crop after capture—changing the browser viewport alone does not guarantee a uniform final canvas.

Settle the page before capturing

waitUntil: 'domcontentloaded' waits for the document’s initial HTML to be parsed, not for every image, font, animation, or client-rendered component to finish. Some pages need a different readiness condition. You can use a selector wait, a short delay, or wait for network activity to quiet down, but each choice has trade-offs: a selector may not exist on every URL, fixed delays add time, and network-idle waits can stall on pages with continuing requests.

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

For pages that reveal images only while scrolling, a full-page screenshot does not necessarily ensure every lazy-loaded asset was requested in advance. If complete image content matters, scroll through the page or wait for a page-specific ready signal before capture, and test that behavior on the target sites.

Rank #4
Sale
Samsung 27" Essential S3 (S36GD) Series FHD 1800R Curved Computer Monitor
  • CURVED FOR ENHANCED ENGAGEMENT: An immersive viewing experience with a curved monitor that wraps more closely around your field of vision; It creates a wider view, enhancing depth perception and minimizing peripheral distraction
  • SMOOTH PERFORMANCE FOR SEAMLESS CONTENT: Stay in the action when playing games, watching videos, or working on creative projects; The 100Hz refresh rate reduces lag and motion blur so you don't miss a thing in fast-paced moments¹
  • MORE GAMING POWER: Gain the edge with optimizable game settings; Color and image contrast can be adjusted to see scenes more vividly and spot enemies hiding in the dark; Game Mode adjusts any game to fill the screen so you can view every detail²
  • KEEP IT EASY ON THE EYES: Care for your eyes and stay comfortable, even during long sessions; Advanced eye comfort technology certified by TÜV reduces eye strain by minimizing blue light and reducing irritating screen flicker²
  • INCREASED VERSATILITY: Connect to more; Plug devices straight into your monitor for increased flexibility, making your computing environment even more convenient

Handle failures, scale, and throughput

Timeouts and selective retries

The example uses a 30-second navigation timeout and does not retry failures. A retry can help with transient network errors, but it cannot fix a permanently blocked or unavailable page. If you add retries, limit the count, record each attempt, and avoid retrying invalid URLs or failures that are clearly permanent.

Concurrency and resource use

The worker pool prevents the script from opening a page for every input simultaneously. More workers can increase throughput, but also increase memory use and load on both your machine and target websites. Start with a conservative value and adjust based on observed completion time, stability, and the sites’ policies. Playwright documents that one browser can have multiple pages; the appropriate batch size is workload-dependent.

Image format and output size

Playwright screenshots can be configured for PNG, JPEG, or WebP; JPEG and WebP support quality settings. The example uses WebP quality 80 as a practical preview-file choice, not a guaranteed best setting. Select the format your consumer accepts and compare visual quality against storage or transfer needs. Screenshot scale also affects output: CSS scale produces one image pixel per CSS pixel, while device scale captures device pixels and can create larger images on high-density displays.

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.
Best Value
Sale
Sceptre New 22-Inch Gaming Monitor, FHD 1080p, Up to 144Hz, HDMI, DisplayPort, Built-in Speakers, Machine Black (E225W-FW144 Series, 2026)
  • 【INTEGRATED SPEAKERS】Whether you're at work or in the midst of an intense gaming session, our built-in speakers provide rich and seamless audio, all while keeping your desk clutter-free.
  • 【EASY ON THE EYES】 Protect your eyes and enhance your comfort with Blue-Light Shift technology. This feature reduces harmful blue light emissions from your screen, helping to alleviate eye strain during long hours of use and promoting healthier viewing habits.
  • 【WIDEN YOUR PERSPECTIVE】Our sleek minimal bezel design ensures undivided attention. The nearly bezel-free display seamlessly connects in a dual monitor arrangement, delivering an unobstructed view that lets you focus on more at once, completely distraction-free.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Protect the capture worker when URLs are untrusted

Allowing users to submit arbitrary URLs can expose the machine running the browser to internal services or private network addresses. The HTTP/HTTPS scheme check in the example is not an SSRF defense. For untrusted input, enforce an allowlist or robust network-level restrictions, block access to loopback, private, link-local, and cloud metadata destinations, and re-check addresses after DNS resolution and redirects. Apply limits to navigation time, page count, file size, and resource consumption as appropriate for your environment.

Or skip the browser setup

ScreenshotNeo offers a website screenshot API and MCP server for developers. Its API can return PNG, JPEG, WebP, or PDF output, and the same endpoint can be called once for each URL in your list. For API parameters and options, see the ScreenshotNeo documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

In a batch script, substitute the current input URL for https://stripe.com and choose a distinct output filename for each request. ScreenshotNeo also accepts the parameter names used by other screenshot APIs, which can make switching easier. Its distinguishing practical details are:

  • Cookie banners are accepted and more than 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 are not billed. Response headers identify the page verdict and whether the request was billed.
  • An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents, including Claude, Cursor, and other MCP clients.
  • The free plan includes 1,000 screenshots per month without a card. Paid plans start at $5 for 3,000 screenshots; yearly billing gives two months free, and every feature is on every plan.

Sign up for 1,000 free screenshots a month with no card.

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

Common problems and fixes

  • Browser executable is missing: run npx playwright install chromium in the project after installing the package.
  • Input file cannot be read: check that urls.txt exists in the current directory, or pass its path as the first script argument.
  • Some rows show invalid_url: correct malformed addresses or supply an explicit HTTP/HTTPS scheme. The script deliberately rejects other schemes.
  • Some pages time out: confirm the destination is reachable from the machine, then adjust navigationTimeoutMs or use a readiness strategy suited to the page. Do not make the timeout unlimited for an uncontrolled list.
  • Thumbnail is blank or incomplete: the page may render content after DOM parsing. Wait for a reliable page-specific selector or state, and account for lazy-loaded content.
  • Images differ in dimensions: use the same viewport and screenshot scale, then resize or crop each image to a fixed canvas if the consumer requires exact dimensions.
  • Job is slow or unstable: lower CONCURRENCY to reduce resource pressure; raise it only after checking memory use and the impact on target sites.
  • Filename appears unexpected: the name is sanitized and truncated for readability, with a hash and row identifier to reduce collisions. Use the manifest as the authoritative mapping.

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.