How to Generate Website Screenshots in Bulk with Cloudinary
Use Cloudinary URL2PNG to capture websites one URL at a time, then automate a queue for multiple targets. Learn the documented options, safeguards, and limits.
Cloudinary documents website screenshots through its URL2PNG add-on: each screenshot is generated on the fly from a dynamic transformation URL for one target website. To capture multiple websites, build a list of targets and request one URL2PNG transformation per target. The documentation reviewed does not establish a dedicated screenshot batch endpoint, a maximum batch size, or a screenshot-specific concurrency limit, so treat bulk generation as an application-level queue rather than a single Cloudinary batch request. Cloudinary URL2PNG documentation
This guide shows how to configure a target capture, organize multiple targets safely, and handle access controls and failures. Cloudinary’s separate bulk-upload guidance concerns uploads; its concurrency advice should not be assumed to apply to screenshot generation.
1. What Cloudinary documents for screenshot capture
Cloudinary’s URL2PNG add-on uses the website URL as the public ID and the url2png delivery type. Cloudinary describes screenshots as generated on the fly from dynamic transformation URLs, then cached and delivered through its CDN. That is a per-target URL workflow. The documentation reviewed does not describe a screenshot batch endpoint.
The URL2PNG guide documents settings including viewport, user_agent, and delay. Its mobile example uses a 640-by-1135 viewport, an iPhone user agent, and fullpage=false. These are examples to adapt to your capture requirements, not settings that every request needs.
The Cloudinary CLI documentation also demonstrates taking a URL2PNG screenshot and applying image transformations such as dimensions, crop position, and grayscale. Transformation behavior can depend on the requested operation and capture, so check the add-on and transformation documentation for the exact output you need.
2. Set up a capture for one target
- Enable and configure the URL2PNG add-on for your Cloudinary account. Confirm the account’s current add-on and transformation access requirements before generating URLs.
- Construct a URL2PNG transformation request for a single target page. Set the viewport and any documented capture options that matter for that page.
- Request the URL and store or deliver the resulting screenshot according to your application’s needs.
- Repeat the per-target operation for each URL in your input list. Add queueing, retries, and output tracking in your own application.
Cloudinary’s URL2PNG documentation contains the canonical URL structure and examples; use those examples with your account configuration rather than guessing at transformation syntax. URL2PNG dynamic URLs may need to be signed or eagerly generated under the documented default access controls. Review URL2PNG setup and URL examples.
3. Turn a list of targets into a bulk workflow
The following Python example illustrates the application-level orchestration pattern: read target URLs, create one configured request per target using your Cloudinary URL2PNG URL builder, and save the resulting image. The URL builder is deliberately a placeholder because the exact transformation path and signing depend on the URL2PNG setup in your Cloudinary account. Use Cloudinary’s documented URL format and signing mechanism in that function.
from pathlib import Path
from urllib.parse import urlparse
# Replace this function with the URL2PNG URL construction and signing
# documented for your Cloudinary account and add-on configuration.
def build_url2png_url(target_url: str) -> str:
raise NotImplementedError("Build and sign the documented URL2PNG URL")
def output_name(target_url: str) -> str:
parsed = urlparse(target_url)
safe_host = (parsed.netloc or "page").replace(":", "_").replace("/", "_")
safe_path = (parsed.path.strip("/") or "home").replace("/", "_")
return f"{safe_host}_{safe_path}.png"
def capture(target_url: str, output_dir: Path) -> Path:
import requests
response = requests.get(build_url2png_url(target_url), timeout=90)
response.raise_for_status()
destination = output_dir / output_name(target_url)
destination.write_bytes(response.content)
return destination
def main() -> None:
targets = [
"https://example.com/",
"https://www.example.org/docs",
]
output_dir = Path("screenshots")
output_dir.mkdir(parents=True, exist_ok=True)
for target in targets:
try:
path = capture(target, output_dir)
print(f"saved {target} -> {path}")
except Exception as exc:
print(f"failed {target}: {exc}")
if __name__ == "__main__":
main()
This is runnable once build_url2png_url is implemented with the URL2PNG transformation structure, options, and signing rules for your account. Keeping URL construction in one function makes the capture settings consistent and lets you rotate or change signing logic centrally. For production, write a result record per target, including the target URL, generated request URL or request identifier as appropriate, output location, and failure reason.
4. Choose capture options deliberately
| Option | When it helps | Consideration |
|---|---|---|
viewport |
Reproducing a desktop or mobile layout at chosen dimensions. | Keep dimensions consistent when comparing pages. Cloudinary’s example includes a 640-by-1135 mobile viewport. |
user_agent |
Requesting a page layout intended for a particular browser or device class. | A different user agent can change the page content and layout; use it only when that is the intended capture context. |
delay |
Allowing a page extra time to render content after navigation. | Longer delays add time to every target. Set only what the target pages require. |
fullpage |
Choosing between a full-page capture and viewport-sized output. | The URL2PNG example demonstrates fullpage=false; check the add-on documentation for supported values and URL syntax. |
Start with a small representative set of pages and verify the rendered output before processing a large list. Pages with different frameworks, responsive layouts, or loading patterns may need different viewport, user-agent, or delay settings.
5. Manage access, signatures, and cost exposure
Cloudinary warns that unplanned dynamic screenshot URLs can create costs. Its URL2PNG documentation says that, by default, image-transformation add-on URLs are required to be eagerly generated or signed using Cloudinary’s authenticated API. Confirm the current behavior and configuration for your account and protect any signing credentials on the server. Do not put secrets into browser code or public source control.
- Validate and constrain the target URLs your application accepts.
- Keep signing credentials server-side and generate protected URLs only where needed.
- Track the number of targets submitted and completed, plus failures and retries.
- Use a bounded queue. The researched screenshot documentation does not give a safe concurrency figure, so choose conservatively and adjust based on account behavior and support guidance.
Cloudinary’s support article about bulk uploads says its Upload API handles one file per call and discusses parallel uploads, including a starting recommendation around 10 simultaneous requests. That advice is specifically for uploads; it is not a screenshot concurrency recommendation. Cloudinary bulk-upload guidance.
6. Troubleshoot common problems
| Symptom | Likely cause | What to do |
|---|---|---|
| Transformation URL is rejected | URL2PNG is not enabled, the transformation path is malformed, or the URL is not signed/eagerly generated as required. | Check the add-on configuration, compare the URL structure with the current URL2PNG examples, and apply the account’s required signing or eager-generation flow. |
| Unexpected transformation or authorization error | The add-on or transformation access settings do not match the request. | Confirm the account’s current configuration and inspect the generated URL for encoding, transformation, and signature mistakes. |
| Screenshot is blank or incomplete | The target page may render slowly, require a different viewport or user agent, or fail to serve expected content to the capture context. | Open the target directly, verify the desired layout, then adjust documented viewport, user-agent, or delay settings and recapture one URL. |
| Some targets fail in a batch | Target-specific failures, transient network problems, or application queue issues. | Record each target’s status independently, retry only failed targets with bounded backoff, and avoid restarting successful captures unnecessarily. |
| Costs are higher than expected | Dynamic screenshot URLs are being generated or requested without the intended controls. | Review URL signing/eager-generation settings and your application’s target and retry logs. Cloudinary specifically warns about cost exposure from unplanned dynamic URLs. |
7. Performance, reliability, and cost notes
A bulk job’s elapsed time depends on the number of targets, their rendering behavior, configured delay, and the amount of work your application performs per capture. A queue lets you cap simultaneous work, resume after interruption, and report partial completion. Because the researched Cloudinary sources do not state screenshot-specific concurrency or batch limits, avoid encoding a numeric limit as a product guarantee.
For reliability, make each target an independent job with a stable identifier. Persist completed outputs, retry transient failures selectively, and keep permanent configuration errors visible rather than retrying them indefinitely. Validate a sample of output dimensions and image content before treating a large run as complete.
Cloudinary’s URL2PNG flow caches and delivers generated screenshots through its CDN, according to its documentation. Consider whether the expected reuse and cache behavior fit your update cadence; the researched sources do not establish a screenshot-specific pricing table or universal cost per capture. Check your current Cloudinary account and add-on terms before estimating spend.
8. When this approach fits
Use the Cloudinary URL2PNG workflow when your project already relies on Cloudinary and its per-target transformation URL model fits the job. It supports documented capture settings and downstream image transformations. For a large list, your application still needs to supply the queue, progress tracking, retry behavior, and concurrency controls, because the sources reviewed do not document a dedicated screenshot batch endpoint.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server for developers. One GET request returns a PNG, JPEG, WebP, or PDF. For example, this cURL request captures a page:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python:
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)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
See the ScreenshotNeo API documentation for request options. ScreenshotNeo removes cookie banners, popups, and chat widgets before the shot; bot checks, blank pages, and failed loads are never billed; and its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000.
Create a free ScreenshotNeo account to get 1,000 screenshots a month with no card.
FAQ
Does Cloudinary document a bulk screenshot endpoint?
The URL2PNG materials reviewed document a per-target dynamic transformation URL, not a dedicated screenshot batch endpoint. That does not prove no other mechanism exists; confirm with current Cloudinary documentation or account support if you need a native batch API.
Can I use Cloudinary’s bulk-upload concurrency recommendation for screenshots?
No. That support guidance addresses bulk uploads through the Upload API. The sources reviewed do not give a screenshot-specific concurrency recommendation.
Can I transform a screenshot after capturing it?
Cloudinary’s CLI guide demonstrates applying image transformations to a URL2PNG screenshot. Check the current transformation documentation for the exact operations and URL syntax you plan to use.


