Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →To screenshot multiple URLs from a CSV, read each row, open its URL in a browser automation tool such as Playwright, and save the result under a unique filename. This Python guide shows a one-image-per-row workflow, how to handle failures and dynamic pages, and when to use full-page captures. If you would rather not run a browser, ScreenshotNeo can capture URLs through a single API request.
What you need before you start
- A CSV file with a header named
urland one URL per row. - Python and the Playwright package. Python’s built-in
csvmodule handles CSV reading; Playwright runs the browser. - An installed browser for Playwright. After installing the package, install Chromium with
playwright install chromium.
Keep the input file simple to start, for example:
url
https://example.com/
https://datasette.io/
Take one screenshot per CSV row with Python and Playwright
Save this script as capture_csv.py beside urls.csv. It validates the header, skips blank rows, uses a row-based filename so duplicate URLs do not overwrite each other, and logs row-level failures instead of stopping the whole batch. Install Playwright with python -m pip install playwright and install Chromium as noted above.
As an Amazon Associate I earn from qualifying purchases.
import csv
from pathlib import Path
from playwright.sync_api import sync_playwright, TimeoutError as PlaywrightTimeoutError
input_csv = Path("urls.csv")
output_dir = Path("screenshots")
failures_file = Path("screenshot_failures.csv")
output_dir.mkdir(parents=True, exist_ok=True)
with input_csv.open(newline="", encoding="utf-8-sig") as f:
reader = csv.DictReader(f)
if not reader.fieldnames or "url" not in reader.fieldnames:
raise SystemExit("CSV must include a header named 'url'.")
failures = []
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page(viewport={"width": 1440, "height": 900})
page.set_default_navigation_timeout(30_000)
for row_number, row in enumerate(reader, start=2):
url = (row.get("url") or "").strip()
if not url:
failures.append({"row": row_number, "url": "", "error": "Blank URL"})
continue
if not url.startswith(("http://", "https://")):
failures.append({"row": row_number, "url": url, "error": "URL must start with http:// or https://"})
continue
output_path = output_dir / f"row-{row_number:04}.png"
try:
page.goto(url, wait_until="load", timeout=30_000)
page.screenshot(path=str(output_path), full_page=True)
print(f"Saved {output_path} from {url}")
except (PlaywrightTimeoutError, Exception) as exc:
failures.append({"row": row_number, "url": url, "error": str(exc)})
print(f"Failed row {row_number}: {url}: {exc}")
browser.close()
if failures:
with failures_file.open("w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=["row", "url", "error"])
writer.writeheader()
writer.writerows(failures)
print(f"Wrote {len(failures)} failures to {failures_file}")
The output folder contains files such as row-0002.png. The number refers to the original CSV line, which makes it easier to match an image or error to its source row. This uses a single page sequentially; it is a straightforward starting point, not a claim about maximum throughput.
Free tools Windows power users keep installed
One-click scans. No signup required.
Why the script chooses full-page screenshots
full_page=True captures the scrollable document in a tall image. Remove that argument or set it to False to capture only the current viewport, here 1440 by 900 CSS pixels. A viewport shot is useful when you need a consistent first-screen view; a full-page shot is better when the entire document matters. Playwright documents the screenshot path and full-page option in its Screenshots guide.
#1 Best Overall
- 14" diagonal, 1366x768 resolution, HD BrightView LED, Glossy NON-TOUCH Display
Use a more meaningful filename when the CSV has an ID
If your CSV includes a stable, unique identifier column, you can use a sanitized version of it in place of the row number. Do not put a raw URL directly into a filename: URLs contain characters that are awkward or invalid in paths, and repeated URLs can overwrite previous captures unless you add a unique suffix.
Choose readiness, format, and repeatability deliberately
Page readiness is site-dependent
wait_until="load" waits for the page’s load event; it does not guarantee that every delayed image, widget, or client-rendered section is visible. For dynamic sites, wait for a known selector with page.locator(".content-ready").wait_for(), or use a short explicit delay only when you understand what it is waiting for. Avoid assuming that one wait condition works for every site.
Choose image format and scale for the destination
Playwright supports PNG, JPEG, and WebP screenshots, along with options such as scale and JPEG quality. PNG is a lossless choice; JPEG can reduce file size for photographic content, while WebP may suit workflows that accept that format. The best option depends on where the images will be used and how much storage you want to spend; no format is universally best. Consult the installed Playwright version’s screenshot documentation for supported options.
Make visual comparisons repeatable
Browser, operating system, and font rendering differences can change screenshots. If these images will be compared against visual baselines, use the same browser and environment for each run. Playwright describes these cross-browser and cross-platform differences in its Visual comparisons documentation.
Rank #2
- 256 GB SSD of storage.
- Multitasking is easy with 16GB of RAM
- Equipped with a blazing fast Core i5 2.00 GHz processor.
Convert a CSV for shot-scraper’s multi-page workflow
shot-scraper multi accepts YAML entries, not a CSV file directly. To use it, convert the CSV URLs into a YAML list, then pass that file to the command. Its documented example format is:
- url: https://example.com/
- url: https://datasette.io/
Save the converted entries as shots.yml and run shot-scraper multi shots.yml. The tool documents one output screenshot per entry and supports options for output filenames and multi-page captures. Check the documentation for the version installed before relying on specific options. For larger batches that record network traffic, it supports --har and --har-zip; its documentation warns that uncompressed HAR data can grow enough to cause Playwright to crash, and recommends --har-zip for larger captures. See the shot-scraper multi documentation.
Or skip the browser setup
ScreenshotNeo offers a screenshot API and MCP server for developers. Its API accepts one GET request with a URL and returns an image or PDF. For example, this cURL call saves a WebP screenshot of one URL:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
For bulk work, send one request per CSV URL and save each response under a unique filename. The API supports PNG, JPEG, and WebP, and ScreenshotNeo documents its options and request parameters in the API documentation.
Rank #3
- WINDOWS 11 | STABLE PERFORMANCE: Powered by Intel Celeron N4020 processor and Windows 11 system, this laptop delivers stable performance for everyday computing tasks. It supports web browsing, online learning, document editing, email communication, and basic office work with optimized power efficiency, providing a practical and reliable experience for essential daily use for daily use.
- 15.6” FHD IPS DISPLAY: Features a 15.6-inch Full HD IPS display with narrow bezels, offering wider viewing angles and clearer image details compared to standard panels. The improved screen-to-body ratio enhances visual experience for study, reading, document work, and video playback, making it suitable for both productivity and entertainment use.
- 4GB DDR4 + 128GB eMMC STORAGE: Equipped with 4GB DDR4 memory and 128GB eMMC storage for everyday basics such as browsing, documents, email, and online learning platforms. The built-in TF card slot supports storage expansion up to 1TB, giving you more flexibility for files, photos, videos, and daily documents. TF card not included.
- CONNECTIVITY & PORTS: Includes 1× TF card slot, 2× USB 3.2 Gen1 ports, and 2× full-featured Type-C ports (USB 3.2 Gen1). The Type-C ports support data transfer, charging, and video output, enabling flexible connection with external devices such as monitors, storage, and peripherals for daily work and study use.
- LIGHTWEIGHT DESIGN | ONLINE COMMUNICATION: Designed with a slim, portable profile, this laptop is easy to carry for school, commuting, and travel. A built-in 1MP front camera supports online classes, video meetings, remote communication, and everyday conferencing. The 3300mAh battery works with the low-power system design to support practical daily use, while thermal optimization helps maintain quieter operation during extended tasks.
- It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be turned off.
- Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed. Responses include
X-Page-VerdictandX-Billedheaders. - Its MCP server provides
take_screenshot,get_page_info, andcapture_pdftools 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; every feature is on every plan.
Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month without a card.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshooting a CSV screenshot batch
- “CSV must include a header named ‘url’”: Add a first-row header spelled exactly
url, or change the script to match your column name. - URL errors or browser navigation failures: Check for blank values, missing
https://orhttp://, malformed addresses, and URLs that redirect to inaccessible destinations. The script writes each failure toscreenshot_failures.csv. - Navigation timeout: The site may be slow or never reach the selected load event. Check the address in a browser, adjust the timeout for your workload, or use an appropriate site-specific readiness condition. A longer timeout can also make a batch take longer.
- Screenshot misses late content: The load event may happen before lazy images or client-rendered elements appear. Wait for a meaningful selector or a deliberate delay rather than assuming the page is visually complete.
- Files overwrite one another: Use a row number or unique ID in the output name, not a potentially repeated URL alone.
- Browser installation or launch fails: Install the Playwright browser matching your package with
playwright install chromium; if necessary, verify that the installed Playwright package and browser are compatible. - Visual output changes between runs: Keep the browser, operating system, fonts, viewport, and capture settings consistent when comparing images.
Batch performance, reliability, and cost
The Python example processes URLs sequentially with one browser page, which keeps the workflow simple and failure logging clear. Runtime depends on the sites, network, readiness waits, and screenshot size; the sources do not establish a universal capture speed. For large runs, consider whether parallel pages or separate workers are appropriate for your environment, and keep per-URL timeouts and error records so a single unavailable site does not hide the rest of the batch. More concurrency can increase resource use and may trigger rate limits on target sites.
Local browser capture runs on your machine and does not have a per-shot API charge, but requires browser installation and your own execution capacity. A managed API trades setup and local browser maintenance for provider pricing and request handling. ScreenshotNeo lists plans from a free 1,000 shots per month to paid tiers; confirm the current plan details on ScreenshotNeo before choosing a hosted workflow.
Frequently Asked Questions
How do I screenshot multiple URLs at once?
Put the URLs in a CSV column named url, then loop through the rows and save one uniquely named image per URL with a browser automation tool such as Playwright.
Can shot-scraper import a CSV directly?
No. Its documented multi input is YAML, so convert the CSV rows to YAML entries before running shot-scraper multi.
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.




