Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitchesTo 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.
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.
#1 Best Overall
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';
Recommended Free Tools
Rank #2
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.
Rank #3
- 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
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.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.
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.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11For 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.
Quick Recap
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.




