Taking one screenshot with code is a fifteen minute job. Taking ten thousand is a different job entirely, and the script that nailed the first one is usually the reason the batch falls over. By the end of this you'll know how to size a batch against a rate limit, what to retry versus what to drop, and what 10,000 screenshots actually costs.
The short version: put a queue between your URL list and your capture call, cap the number of requests in flight to match your rate limit, retry failures on a separate pass instead of inline, and persist each result before you move on. Everything below is the detail behind those four rules.
What are automated website screenshots?
Automated website screenshots are page captures produced by code, in bulk or on a schedule, with nobody clicking a capture button. The distinction that matters is not the tooling, it is the volume: one capture is a function call, and ten thousand captures is a pipeline with a failure budget.
Most automation work lands in one of four buckets:
- Thumbnails and link previews for a directory, marketplace, or feed, where every listed URL needs an image.
- Open Graph and social card images generated per page at publish time.
- Archival snapshots, where the picture is the record of what a page looked like on a given day.
- Feeding a model, where a vision model needs the rendered page rather than the raw HTML.
All four have the same shape: many URLs, one capture each, run unattended. That is the case this post is about. With ScreenshotRender a single capture is one GET request, so the interesting engineering is not the request itself, it is everything wrapped around ten thousand of them.
Why does a screenshot script break at a thousand URLs?
Because the two obvious ways to write the loop both fail, in opposite directions. Awaiting one capture at a time is correct and unusably slow. Firing all of them at once is fast for about four seconds and then collapses.
The serial version is the one everyone writes first. It reads well and the arithmetic is brutal. Call a capture four seconds, which is the two second settle the API waits by default plus a page load on top: ten thousand URLs is then over eleven hours in a single process, and any crash at hour nine starts you from the top. So the instinct is to drop the await and let them all go, which produces a different set of problems:
- Rate limiting. Ten thousand simultaneous requests earn you a wall of 429 Too Many Requests responses, and a naive script treats those as permanent failures.
- Memory. If you are driving your own browser rather than calling an API, every concurrent page is a live renderer, and the Puppeteer troubleshooting guide exists largely because of what that does to a container.
- No failure isolation. One unhandled rejection in a batch of ten thousand takes the whole process down, and without per-URL persistence you have no idea which ones finished.
Worth naming what this post is not about, because two adjacent jobs get solved differently. Capturing one page repeatedly to spot what changed is website change detection, and comparing captures against a baseline in CI is visual regression testing. Both are one URL over time. This is many URLs, once.
How do you automate website screenshots?
You put a bounded queue between your URL list and the capture call, then treat every capture as an independent unit of work that can fail without taking its neighbours with it. Concretely, five stages:
- Enumerate and deduplicate. Build the URL list up front and write it somewhere durable. Deduplicating first is free and on a real list it usually removes more work than any optimisation further down.
- Bound the concurrency. Pick a worker pool size from your rate limit, not from your CPU count. This is the single number that decides whether the batch runs clean.
- Capture. One request per URL. With ScreenshotRender that is one line:
https://screenshotrender.com/api/v1/screenshot?apiKey=YOUR_API_KEY&url=https://en.wikipedia.org/wiki/HTTP&fullPage=true. Your API key is thesr-string on your dashboard,fullPage=truecaptures the whole scrollable page instead of the viewport, andwaitandtimeoutboth take seconds. - Persist immediately. The response is JSON with a hosted image URL plus the page title, description, and favicon. Write that row before starting the next URL so a crash costs you one capture rather than the run.
- Sweep the failures. Collect everything that did not succeed and retry it as a second, smaller pass once the main batch is done. Retrying inline just slows the queue behind it.
Stage five is the one people skip, and it is the one that decides whether you ship the batch or spend the next morning working out which rows are missing.
Ten thousand screenshots, zero browsers to babysit.
Skip the Chromium builds, the memory tuning, and the anti-bot arms race. ScreenshotRender renders every page on its own fleet and hands back a hosted image, so your pipeline is a loop and an HTTP call.
Start rendering freeHow many screenshots can you capture per minute?
On ScreenshotRender, between 40 and 150 requests per minute depending on your plan: 40 on the free plan, 60 on Hobby, 80 on Standard, and 150 on Growth. That number, divided by sixty, is the only input your worker pool sizing needs.
Standard's 80 requests per minute is roughly 1.3 per second. If a capture averages four seconds end to end, you need about five or six workers in flight to saturate that limit, and adding a twentieth worker buys you nothing except 429s. Size the pool to the limit, then leave it alone.
When you do hit a 429, back off rather than hammer. The standard approach is exponential backoff with jitter: double the delay on each retry and add a small random offset so your workers do not all wake up at the same instant and re-collide. Three retries on that curve clears almost every transient failure.
Two other status codes deserve explicit handling. A 401 means the API key is wrong and every remaining request will fail the same way, so stop the batch. A 402 means the credits are gone, which is also fatal to the run but recoverable by topping up. Neither is worth retrying.
What does it cost to capture 10,000 screenshots?
On the Standard plan, 59 dollars a month covers exactly 10,000 screenshots, which is 0.0059 per capture, or 0.0049 if you pay annually at 49 dollars a month. Above that the tiers are 14 dollars for 2,000 on Hobby and 239 dollars for 50,000 on Growth, and the free plan gives you 100 screenshots with no card so you can size a real batch before committing.
Overage runs on the same curve rather than a penalty rate: 0.007 per extra capture on Hobby, 0.005 on Standard, 0.004 on Growth. A batch that overshoots its plan by a few hundred captures costs a couple of dollars, not a surprise invoice.
The part that changes how you write the code is that credits are only deducted after a capture succeeds, on every plan. In a batch of ten thousand real URLs you will always have dead domains, redirect loops, and pages that never settle, and none of those are billed. That is what makes an aggressive retry sweep the right default: a failed attempt costs you a few seconds of queue time and nothing else. Repeat captures of the same page with the same options are served from cache and do not count either.
Compare that against the alternative honestly. Running your own fleet looks cheaper per capture right up until you price the Chromium upgrades, the memory tuning, the font packages, and the hours lost to headless Chrome on serverless. Ad blocking, cookie banner removal, and caching are already on every ScreenshotRender tier, including the free one.
When does screenshot automation stop working?
When the pages need a session, when the real job is one page over time rather than many pages once, and when what you actually need is the text rather than the picture. Being clear about the limits:
- Pages behind a login. The API renders public URLs. A page that requires an authenticated session, and that includes the major social platforms, returns the login wall, not the content. No retry policy fixes that.
- Pages that never settle. Infinite scroll, autoplaying video, and animation loops mean there is no moment where the page is done. Raise
waitto catch late content and set atimeoutso a pathological page cannot stall a worker forever, then accept that some captures land mid-animation. - When you want data, not pixels. If the end goal is prices or headlines, an image is a lossy detour. Screenshots earn their place when the visual record itself is the deliverable, or when a vision model is the consumer.
- Very small batches. Under about fifty URLs, the queue and the retry sweep are more machinery than the problem deserves. A serial loop finishes in three minutes and you can watch it.
The honest test is whether the batch is big enough that you will not babysit it. Below that line, write the simple loop.
Common questions about automated website screenshots
How do I automate taking screenshots of a website?
Call a screenshot API from your own code instead of driving a browser by hand. With ScreenshotRender the whole capture is one GET request to https://screenshotrender.com/api/v1/screenshot with your apiKey and the target url, and the response is JSON containing a hosted image URL. Wrap that call in whatever runs your jobs already, a cron entry, a queue worker, or a no-code scenario in Zapier, Make, or n8n, and you have automation without a browser to maintain.
Can I screenshot multiple URLs at once?
Yes, but you drive the concurrency, not the API. There is no bulk endpoint that accepts an array of URLs, so you send one request per URL and control how many are in flight from your own worker pool. Size that pool against your plan's per-minute rate limit, from 40 requests per minute on the free plan up to 150 on Growth, and the batch runs at full speed without tripping anything.
Do failed screenshots count against my quota?
No. A credit is only deducted after a capture actually succeeds, on every plan including the free one. That matters more in automation than anywhere else, because a large batch always contains dead domains, timeouts, and pages that never finish loading. You are not paying for that noise, so an aggressive retry policy costs you time rather than money.
How long does one automated screenshot take?
Long enough that you should never assume it is instant. The API waits two seconds for the page to settle before capturing unless you override it, and the page load happens on top of that, so a capture is a multi-second operation. Raise it with wait for slow pages, cap the attempt with timeout, and plan batch throughput around the rate limit rather than around one request's latency.
Is it cheaper to run my own headless browser?
Rarely, once you count the time. The per-capture compute looks cheap in isolation, but you are also buying Chromium upgrades, memory tuning, font packages, retry logic, and the ongoing churn in headless Chrome itself, none of which appears on the server bill. Standard is 59 dollars for 10,000 captures with the fleet, the cleanup, and the caching included.
Wrapping up
Automating website screenshots at volume is mostly a queueing problem wearing a rendering costume. Bound your concurrency to the rate limit, persist every result the moment it lands, sweep the failures on a second pass, and let pay-per-success billing make that sweep free. Do those four things and ten thousand URLs is an overnight job you do not have to watch.



