DriversRecommendedOutdated drivers can make a good PC feel brokenScan driver issues before chasing fixes manually.Scan NowOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PC×
Skip to content
World desk7 min

How to Bulk Screenshot URLs and Detect Blank Images with Playwright

Capture a list of URLs with Playwright and use a calibrated pixel-variation heuristic to flag blank-looking screenshots without confusing them with navigation failures.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To bulk screenshot a URL list and flag blank-looking captures, use Playwright to visit each URL, save a screenshot, and measure image variation afterward. Keep navigation failures separate from image classifications: a low-variation image is a review flag, not proof that the page failed to render.

What this workflow can—and cannot—tell you

Playwright’s Page API can navigate to a URL and save a screenshot, either to a file or as bytes for later processing. You can capture the viewport or use fullPage: true to include the page’s scrollable content. The API does not provide a universal blank-image detector; the content test below is an application-level heuristic. Playwright Page API · Playwright screenshots documentation

As an Amazon Associate I earn from qualifying purchases.

For a batch, record capture status independently from blankness. A timeout, navigation error, or blocked request is not the same result as a successful screenshot whose pixels happen to be uniform. A nearly solid image may be an intentionally minimal design, a consent screen, a loading state, or a failed render. Inspect flagged files and calibrate the threshold using pages representative of your own list.

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

Set up a repeatable batch capture

Install Playwright and prepare the URL list

This Node.js example reads one URL per line from urls.txt, starts one Chromium process, visits each URL sequentially, saves successful screenshots, and writes a JSON Lines manifest. Sequential navigation is a conservative starting point; increase concurrency only after checking memory, CPU, and target-site limits.

npm init -y
npm install playwright
npx playwright install chromium

Create urls.txt with one address per line. Lines beginning with # and blank lines are ignored.

Capture images and classify low-variation results

Save the following as capture.mjs. The example uses sharp to resize each image to a small grayscale sample and calculate luminance standard deviation. The cutoff is deliberately configurable: 5 is only an initial value, not a universal definition of blank. Validate it against known pages before using the label operationally.

npm install sharp

import { chromium } from 'playwright';
import sharp from 'sharp';
import { readFile, mkdir, appendFile } from 'node:fs/promises';

const urls = (await readFile('urls.txt', 'utf8'))
  .split(/r?n/)
  .map(line => line.trim())
  .filter(line => line && !line.startsWith('#'));

const outDir = 'screenshots';
await mkdir(outDir, { recursive: true });
await writeFile('manifest.jsonl', '', 'utf8').catch(() => {});

const browser = await chromium.launch({ headless: true });

async function luminanceStdDev(buffer) {
  const { data } = await sharp(buffer)
    .resize({ width: 64, height: 64, fit: 'fill' })
    .greyscale()
    .raw()
    .toBuffer({ resolveWithObject: true });
  const mean = data.reduce((sum, value) => sum + value, 0) / data.length;
  const variance = data.reduce((sum, value) => sum + (value - mean) ** 2, 0) / data.length;
  return Math.sqrt(variance);
}

for (let i = 0; i < urls.length; i++) {
  const url = urls[i];
  const id = String(i + 1).padStart(5, '0');
  const path = `${outDir}/${id}.png`;
  const page = await browser.newPage({ viewport: { width: 1365, height: 900 } });
  const startedAt = new Date().toISOString();
  const record = { id, url, startedAt, screenshot: null, finalUrl: null, navigationError: null, blankCandidate: null, luminanceStdDev: null };

  try {
    const response = await page.goto(url, { waitUntil: 'load', timeout: 30000 });
    record.finalUrl = page.url();
    record.httpStatus = response?.status() ?? null;
    const image = await page.screenshot({ path, fullPage: false });
    record.screenshot = path;
    record.imageSize = await sharp(image).metadata().then(({ width, height }) => ({ width, height }));
    record.luminanceStdDev = await luminanceStdDev(image);
    record.blankCandidate = record.luminanceStdDev < 5;
  } catch (error) {
    record.navigationError = String(error);
  } finally {
    record.finishedAt = new Date().toISOString();
    await appendFile('manifest.jsonl', `${JSON.stringify(record)}n`);
    await page.close();
  }
}

await browser.close();

There is one correction needed for the script as written: it calls writeFile but does not import it. Add it to the node:fs/promises import, or remove the manifest-clearing line and delete the old manifest before each run. The proper import is import { readFile, mkdir, appendFile, writeFile } from 'node:fs/promises';

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

The script records the final URL and HTTP status when navigation returns a response; neither value alone establishes that the page is visually healthy. It saves a screenshot only after navigation resolves. To capture an error page or partial rendering for diagnosis, move screenshot creation into a separate guarded step after navigation handling, and record its outcome distinctly.

Choose viewport or full-page capture deliberately

The example captures only the initial viewport. Change the screenshot call to page.screenshot({ path, fullPage: true }) when content below the fold matters. Full-page images can be much taller and larger; a single unusual section can also raise pixel variation enough to conceal a blank viewport or failed region. Decide which kind of failure you need to detect and inspect the corresponding image region.

Calibrate the blank-image heuristic

Interpret the score as a triage signal

The example downsamples to 64 × 64 grayscale pixels and computes population standard deviation. Low deviation means sampled luminance values are similar; it does not mean Playwright detected a browser error. Color variation could be measured instead, but either approach needs a threshold selected for the expected content and capture conditions.

  • Test known ordinary pages, intentionally sparse pages, dark pages, consent screens, and likely loading or error states.
  • Review false positives (valid flat-color or minimal pages) and false negatives (mostly blank pages with a small, high-contrast element).
  • Keep the metric, resize method, viewport, and threshold fixed when comparing runs.
  • Store the image and score so a reviewer can verify flagged results rather than treating the score as a verdict.

If the goal is to detect changes from an expected page state rather than discover unknown blankness, use visual regression assertions with reference screenshots. Playwright Test’s toHaveScreenshot() waits for two consecutive screenshots to match before comparing against the expected snapshot; configurable options include animation handling, caret handling, scale, thresholds, pixel-difference tolerances, and timeouts. It is a baseline comparison, not a generic blank-page classifier. Playwright visual comparisons · PageAssertions options

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

Make batch results reliable and manageable

Capture conditions and dynamic pages

Rendering can vary with operating system, browser version, settings, hardware, power source, and headless mode. For repeatable comparisons, keep those conditions consistent and use the same viewport and capture settings. Dynamic content, ads, animations, and delayed assets can also change a screenshot between runs; a stable-looking score is meaningful only relative to a controlled capture procedure.

Batch size, timeouts, and resource use

One browser process avoids repeatedly paying startup overhead, while a fresh page per URL isolates page state. Sequential capture is slower than parallel work but limits resource spikes. For larger lists, introduce a small bounded number of concurrent pages, monitor browser memory, and respect destination-site policies. Set navigation timeouts according to the sites you expect; record timeout as a capture outcome rather than silently dropping that URL.

Keep a useful manifest

For each input, retain a stable ID, original URL, start and finish timestamps, final URL, HTTP response status when available, error or timeout, screenshot path, dimensions, and detector score. This makes it possible to distinguish a missing file from a failed navigation and a low-variation candidate from a normal capture. Avoid using a URL alone as a filename: repeated URLs, query strings, and unsafe characters complicate output management.

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

Troubleshooting common outcomes

No screenshot was saved

Check the manifest for a navigation exception or timeout. Confirm the URL is reachable from the machine running Chromium, that Chromium was installed with Playwright, and that the output directory is writable. If navigation errors are being caught, ensure the error text is retained instead of discarded.

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

Many pages are flagged as blank

The cutoff may be too high, or your target pages may genuinely be low-detail, dark, or dominated by a single background. Inspect a sample of flagged files, then adjust the threshold using known-valid and known-problem examples. Do not interpret a batch of low scores as proof of a shared browser failure without checking captures and navigation records.

A failed or blocked page looks nonblank

A CAPTCHA, consent screen, browser error page, or partial load can contain substantial visual detail and therefore pass a variation test. Pixel variation detects image texture, not semantic success. Use HTTP/navigation records and, where appropriate, site-specific checks alongside image review.

The same page differs across runs

Standardize the browser version, operating environment, viewport, and headless setting. Then investigate page animations, delayed content, or other changing elements. Playwright’s visual assertion stabilization helps with baseline testing, but does not guarantee that all external page content is deterministic.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server for developers. A single request can return an image or PDF; its API can also process URL batches. Cookie banners are accepted like a visitor and 60+ known consent platforms, newsletter popups, and chat widgets are removed before capture, with each step independently switchable. Bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed; responses identify the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for AI-agent clients.

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

For a quick single-URL test, replace the sample URL and key:

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

See the ScreenshotNeo API documentation for request options, including bulk capture and response details. A low-variation image still needs content-based review; do not treat any screenshot API’s successful response as a universal blank-image diagnosis. ScreenshotNeo includes 1,000 screenshots a month free with no card; paid plans start at $5 for 3,000. Sign up free for ScreenshotNeo.

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

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

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Windows Errors? Fix Them Before They SpreadFree repair scan
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.