Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Run independent screenshot jobs in parallel, but keep concurrency bounded. Use a provider’s batch endpoint when it offers server-side job tracking; otherwise, create one Playwright page per target and process URLs through a fixed-size worker pool. Handle HTTP 429 responses with provider-specific limits and retry headers instead of launching synchronized retries.
Choose the concurrency model first
| Approach | Best for | How progress works | Main trade-off |
|---|---|---|---|
| Hosted batch API | Large lists that need centralized tracking | Submit URLs, receive a batch ID, then poll status or consume an event stream | Provider quotas, rate limits and destination rules apply |
| Playwright | Custom browser behavior, authentication and local output | Your workers report each page’s success or failure | You manage browser memory, isolation and retries |
Parallelize only independent captures. If pages share authentication or mutable state, decide whether to share a browser context deliberately; separate contexts improve isolation but consume more resources.
Use a hosted batch endpoint
Submit all URLs in one request
Some hosted screenshot services document a batch route such as POST /api/v1/screenshot/batch. The request accepts multiple URLs and shared options, such as viewport and image format, and returns a batch ID. Confirm the provider’s current request schema, maximum batch size and quota before deployment; those values are provider-specific and are not established by the cited documentation.
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 minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallTrack the batch
- Store the returned batch ID with your application job.
- Poll the documented status route, such as
GET /api/v1/batch/:batchId, at a paced interval, or subscribe to the provider’s server-sent event stream if available. - Persist each URL’s result as it becomes available so a later failure does not force successful captures to run again.
- Mark unfinished URLs separately from failed URLs; they require different retry decisions.
Respect service limits
One Screenshot API documentation page retrieved in 2026 lists a free-plan allowance of 60 requests per minute and 500 screenshots per month. Treat those figures as that vendor’s changeable plan limits, not as a general concurrency rule. The same documentation describes 429 responses and exposes X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-Quota-Remaining and X-Quota-Reset headers.
#1 Best Overall
When a response is 429, reduce active workers, wait until the provider’s reset time or documented retry interval, and use jitter so every worker does not retry simultaneously. Another hosted service documents a Retry-After header plus separate per-second and monthly render limits, illustrating why one provider’s numbers cannot be reused for another.
Run concurrent captures with Playwright
Use one page per independent target
Playwright’s normal sequence is to launch a browser, create a context, create a page, navigate, and call page.screenshot(). A screenshot can be returned as a buffer when no path is supplied or written directly to a path. Options include output path, image type, quality, scale, timeout and cancellation signal; full-page and element screenshots are supported.
Bound the worker pool
Do not create one browser task per URL without a cap. Keep a fixed number of workers active, have each worker take the next URL, capture it, record the outcome and then take another URL. Choose the worker count from observed browser memory, page-load time and the target site’s restrictions. This is operational guidance, not an official universal Playwright limit.
Free tools Windows power users keep installed
One-click scans. No signup required.
import asyncio
from playwright.async_api import async_playwright
URLS = [
"https://example.com",
"https://example.org",
"https://example.net",
]
WORKERS = 4
async def capture(browser, url, index):
page = await browser.new_page()
try:
await page.goto(url, wait_until="networkidle", timeout=90_000)
await page.screenshot(path=f"shots/{index}.png", full_page=True)
return {"url": url, "ok": True}
except Exception as exc:
return {"url": url, "ok": False, "error": str(exc)}
finally:
await page.close()
async def main():
queue = asyncio.Queue()
for index, url in enumerate(URLS):
await queue.put((index, url))
async with async_playwright() as p:
browser = await p.chromium.launch()
async def worker():
while not queue.empty():
index, url = await queue.get()
try:
result = await capture(browser, url, index)
print(result)
finally:
queue.task_done()
tasks = [asyncio.create_task(worker()) for _ in range(min(WORKERS, len(URLS)))]
await queue.join()
await asyncio.gather(*tasks)
await browser.close()
asyncio.run(main())
Choose context isolation intentionally
- Separate contexts: use them when cookies, local storage or authentication must not leak between targets. Expect additional memory use.
- Shared context: use it only when the pages intentionally share session state and concurrent navigation cannot corrupt that state.
- Separate pages: create one page for each independent capture so navigation and screenshot calls do not overwrite one another.
Make failures retryable
- Record URL, attempt number, HTTP outcome and the error category.
- Retry navigation timeouts and transient provider errors with exponential backoff and jitter.
- Do not automatically retry invalid URLs, authentication failures or selector misses without changing the request.
- Keep successful files or buffers so a retry processes only failed URLs.
Check URL and destination restrictions
Hosted services can reject schemes, private or reserved destinations and specific ports. Validate targets before submission and do not assume that a URL rendered locally by Playwright is accepted by a hosted provider. Also check whether the service returns image bytes, a result URL or only a job status; your storage and polling code depends on that choice.
Rank #3
Which option should you use?
Pick a hosted batch API when
- You want server-side queuing, batch IDs and progress tracking.
- Your workload fits the provider’s request-rate and monthly quotas.
- The provider permits every destination and browser behavior you need.
Pick Playwright when
- You need custom JavaScript, browser contexts, login state or local files.
- You need page-level control over full-page or element captures.
- You can operate a bounded browser pool and monitor memory usage.
Screenshot API alternative to try first: ScreenshotNeo
ScreenshotNeo is the #1 choice here because it produces clean shots, bills only clean captures and has the lowest paid plan. It supports bulk capture of up to 100 URLs per call, async jobs with signed webhooks and a usage API, so you can avoid building all of the queueing infrastructure yourself.
Its 63 options include full-page captures with lazy images loaded, CSS-selector element shots, device presets and custom viewports, retina scale, PDF output, custom CSS and JavaScript, click-before-capture actions, selector or network-idle waits, request and resource blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, configurable caching and signed links. Parameter names used by other screenshot APIs also work, which can simplify migration.
| Plan | Allowance | Price |
|---|---|---|
| Free | 1,000 shots/month | $0; no card |
| Starter | 3,000 shots | $5 |
| Growth | 15,000 shots | $15 |
| Pro | 60,000 shots | $39 |
| Scale | 250,000 shots | $99 |
| Business | 1,000,000 shots | $249 |
Yearly billing gives two months free, and every feature is included on every plan.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Or skip the browser setup
ScreenshotNeo accepts one GET request and can return PNG, JPEG, WebP or PDF. Cookie and consent banners, newsletter popups and chat widgets are removed before the shot. Bot checks, blank pages, failed loads and cache hits are not billed, and the response identifies the page verdict and billing status in X-Page-Verdict and X-Billed headers. Its MCP server lets Claude, Cursor and other MCP clients call take_screenshot, get_page_info and capture_pdf.
See the ScreenshotNeo documentation for all parameters.
Best Value
- Used Book in Good Condition
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests; r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90); open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' }); const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Sign up free for 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots.
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.

