How to Capture Bulk Screenshots on a Raspberry Pi with Chromium
Capture a list of web pages on a Raspberry Pi with Chromium headless, save each image under a unique filename, and handle timeouts and common failures.
To capture bulk website screenshots on a Raspberry Pi, run Chromium in headless mode once per URL with --screenshot, set a viewport with --window-size, and move each generated screenshot.png to a unique filename before the next capture. Chromium writes that default filename in the current working directory, so leaving every result there overwrites earlier captures.
This guide covers page screenshots, not pictures of the Raspberry Pi desktop. The commands below are patterns based on Chromium’s documented CLI; they have not been run on a Raspberry Pi. Check the Chromium binary and switches installed on your own system before scheduling a large batch. Chromium’s Headless documentation and Chrome for Developers’ headless guide describe the current headless approach.
1. Check Chromium on the Raspberry Pi
Open a terminal and identify the executable available on the system. The command name can vary by installation; Chromium’s switch guidance uses chromium-browser as a Linux example, but do not assume that exact name is installed on every Raspberry Pi OS release.
command -v chromium
command -v chromium-browser
command -v google-chrome
Use the path returned by command -v in the commands that follow. If none returns a path, install or locate a Chromium package compatible with your OS before proceeding. To check the installed browser version, invoke the binary with its version option:
chromium --version
Replace chromium with the executable you found. Chromium switches can change or be removed, so confirm that the installed build accepts the flags you plan to use. You can also inspect the effective command line at chrome://version in a browser window, as described in the Chromium command-line switch reference.
2. Capture one page first
Try one URL before making a batch. This example requests a 1280 by 1696 browser viewport and waits up to 5 seconds before capture:
chromium --headless --screenshot --window-size=1280,1696 --timeout=5000 https://example.com
Use the binary name available on your Pi. The documented default output is screenshot.png in the current directory. Confirm that the file exists and inspect whether the visible content, viewport, and page load time are appropriate for your targets.
--window-size=WIDTH,HEIGHT controls the viewport dimensions. Choose dimensions that match the layout you want to capture. This is a viewport capture; do not assume that it includes the entire page vertically. The documented CLI example supports --timeout in milliseconds. It sets a maximum wait before capture, but it cannot guarantee that every site’s delayed scripts, images, or asynchronous data have finished rendering.
3. Capture a URL list without overwriting files
Put one URL per line in a UTF-8 text file named urls.txt. Then run a loop that assigns each input line a numbered output filename:
mkdir -p captures
index=0
while IFS= read -r url || [ -n "$url" ]; do
[ -z "$url" ] && continue
index=$((index + 1))
chromium --headless --screenshot --window-size=1280,1696 --timeout=10000 "$url"
if [ -f screenshot.png ]; then
mv screenshot.png "captures/shot-$(printf '%05d' "$index").png"
else
printf 'No screenshot produced for item %s: %s\n' "$index" "$url" >&2
fi
done < urls.txt
Save this as a shell script or paste it into a Bash-compatible terminal from the directory where you want the temporary Chromium output. The numbered filenames avoid putting untrusted URL text into filesystem paths, and the destination directory keeps the batch together. The loop is sequential: it launches a capture, moves the default output if present, and then reads the next URL.
For a small hand-curated batch, you can use descriptive filenames instead, but sanitize URL-derived names: URLs contain characters that are unsuitable or confusing in filenames. Keep the original URL list alongside the numbered outputs if you need a reliable mapping from image to source.
Keep a capture log
For scheduled or repeatable work, log the input URL and result filename for each item. This simple variant records successful output paths and reports missing files; Chromium diagnostics remain on the terminal unless you redirect them.
mkdir -p captures
index=0
while IFS= read -r url || [ -n "$url" ]; do
[ -z "$url" ] && continue
index=$((index + 1))
name="shot-$(printf '%05d' "$index").png"
if chromium --headless --screenshot --window-size=1280,1696 --timeout=10000 "$url"; then
if [ -f screenshot.png ]; then
mv screenshot.png "captures/$name"
printf '%s\t%s\n' "$name" "$url" >> captures/manifest.tsv
else
printf 'Missing output\t%s\n' "$url" >> captures/errors.tsv
fi
else
printf 'Chromium command failed\t%s\n' "$url" >> captures/errors.tsv
fi
done < urls.txt
This is an illustrative shell pattern, not a tested Raspberry Pi script. Chromium may return a nonzero status for a page even when it created an image, or behave differently across versions. Inspect both the output files and logs for your installed build, and adjust the success checks to match your workflow.
4. Choose a capture wait and inspect the result
Start with a representative sample of your target sites. Increase --timeout for pages that need longer to render, then inspect the resulting images for missing content. A timeout is an upper bound on waiting, not a page-specific readiness check. A page that paints its shell quickly but fills in content later may still be captured too early.
- Use a consistent viewport when comparing pages; responsive layouts change with viewport size.
- Use a longer timeout for slower pages, while accounting for the longer run time across the whole list.
- Check pages that require sign-in, client-side rendering, or user interaction separately; this CLI pattern does not configure those conditions.
- Keep a record of URLs that fail or produce incomplete images so they can be retried or handled separately.
5. Headless browser or desktop screenshot?
Use Chromium headless when the target is a rendered web page at a URL and you want to automate repeated captures. Use a desktop screenshot utility when the target is the visible Raspberry Pi display, including its windows, panels, and current screen state. The Raspberry Pi Official Magazine guide to Scrot describes a desktop-capture option. These approaches capture different things: a browser-rendered page versus the current desktop.
6. Common problems and fixes
| Symptom | Likely cause | What to do |
|---|---|---|
command not found |
The executable has a different name or Chromium is not installed. | Check command -v chromium, command -v chromium-browser, and the installed package information. Use the actual executable path. |
| Unknown or ignored switch | The installed Chromium build differs from the documentation or the switch has changed. | Check chromium --version and the switch guidance for that build. Use the supported --headless mode; current Chromium documentation says --headless=old has no effect as of M132, and points users of the old implementation to chrome-headless-shell. |
| Every URL seems to produce the same image | The default screenshot.png was overwritten on each run, or the move did not happen before the next capture. |
Move the file to a unique destination immediately after each invocation, or isolate invocations in distinct working directories. |
| Image is blank or content is missing | The page failed to load, needs more time, or populates content asynchronously. | Try a longer --timeout, inspect Chromium’s output, and review a sample image. A longer timeout does not guarantee that a site’s dynamic content is ready. |
| Screenshot has the wrong dimensions or layout | The requested viewport does not match the desired responsive layout. | Set the intended width and height with --window-size and inspect the saved image’s dimensions. |
| Some input lines are treated unexpectedly | The URL list contains blank lines, whitespace, or malformed URLs. | Keep one complete URL per line, remove unintended whitespace, and skip or validate blank lines before capture. |
| Desktop panels or other windows are absent | Headless Chromium captures a web page, not the visible desktop. | Use a desktop capture utility such as Scrot when you need the screen state. |
7. Performance, reliability, and storage
The Chromium CLI runs one process per URL in the example loop. Total runtime depends on the sites and the wait each capture needs; the available sources do not establish a Raspberry Pi-specific throughput figure, recommended batch size, or memory requirement. Measure a representative sample on your own Pi before deciding how often to run a large batch.
Sequential captures are straightforward to track and avoid concurrent processes competing for local resources, but they can take longer than a concurrent design. Do not assume that increasing concurrency improves throughput on your Pi: test it against the machine, browser build, and target sites you actually use. If a batch is interrupted, retain the URL list and manifest so you can identify which items need retrying.
Each PNG consumes local storage. Check free space before a large run and choose an output location with enough capacity. A microSD card is one possible local storage location, but the sources do not establish a required capacity or speed class. The saved files can also be moved to another storage system after capture.
8. Or skip the browser setup
If you want a screenshot API instead of maintaining a Chromium setup on the Pi, ScreenshotNeo returns a PNG, JPEG, WebP, or PDF from one GET request. See the ScreenshotNeo API documentation for the request options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
Replace YOUR_API_KEY with your API key. The Python example needs the requests package. The Node.js example uses the built-in Fetch API and Bun’s file writer; in Node.js, save the response body using your preferred file-writing method. For example, use await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()))) after checking res.ok.
ScreenshotNeo removes cookie and consent banners, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and the response identifies the page verdict and billing status in headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.
Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.
FAQ
Does this capture the full height of a long page?
The documented command sets a viewport size; do not assume it captures the full page. Inspect the output for your installed build and requirements.
Can I use --headless=old?
Current Chromium Headless documentation says the old implementation is no longer part of the Chrome binary as of M132. Use the supported --headless approach or consult the documentation for your installed build.
Can I capture the Raspberry Pi desktop with this command?
No. This workflow captures a web page in Chromium. Use a desktop screenshot utility for the visible screen.
How many URLs should I put in one batch?
The sources do not specify a safe or recommended batch size for Raspberry Pi. Start with a small representative list, check runtime, output quality, and free storage, then scale to your workload.
Does a five-second timeout mean the page is fully loaded?
No. It limits the wait before capture. Page-specific scripts and delayed content may need more time and still require inspection.


