Bulk Screenshot & PDF Generator
Bulk Screenshot & PDF Generator
Capture full-page screenshots or PDFs from a list of URLs in a single run. Feed it 3 URLs or 3,000 — each one comes back as a PNG, JPG, WebP, or PDF, paired with a metadata row that tells you exactly what happened.
Bulk Screenshot & PDF Generator Features
- Accepts a list of URLs, not one at a time — the whole point of a bulk tool
- Captures PNG, JPG, WebP, or PDF in the same run, picked once for the whole batch
- Desktop, mobile, tablet, or a custom viewport size — your call
- Full-page or viewport-only capture
- Dark mode emulation, for screenshots that don't look like they're from 2015
- Optional CSS selector wait, so you can capture a page after its content actually loads
- Every URL gets exactly one dataset row — success or failure. Nothing gets silently dropped, even navigation timeouts get an error row
- Resumable — pick a large batch back up without re-capturing what already finished
Who Uses a Bulk Screenshot Tool?
- QA engineers — snapshot every page in a release before and after a deploy, then diff them
- SEO teams — pull visual + PDF snapshots of a site's key pages on a schedule
- Brand monitoring — capture how partner or competitor pages render across viewports
- E-commerce ops — archive product pages as PDFs for pricing disputes or catalog audits
- Legal and compliance — capture dated, full-page evidence of a web page's state, in PDF form
- Anyone writing a CI check — visually confirm nothing broke, across a whole URL list, in one run
How It Works
- Give it a list of URLs and pick a format — PNG, JPG, WebP, or PDF.
- Set a viewport (desktop, mobile, tablet, or custom) and, if you want, dark mode.
- It navigates each URL, optionally waits for a selector or a fixed delay, then captures.
- You get one dataset row per URL with the capture's metadata, plus the actual file sitting in the run's key-value store.
Input
{
"urls": [
"https://example.com/",
"https://example.com/pricing",
"https://example.com/about"
],
"format": "png",
"viewport": "desktop",
"fullPage": true,
"darkMode": false,
"waitMs": 1000
}
| Field | Type | Default | Description |
|---|---|---|---|
urls |
array | — | List of URLs to capture. Each one produces one dataset row and one binary in the key-value store. |
format |
string | "png" |
Output format: png, jpg, webp, or pdf. Applies to the whole run. |
viewport |
string | "desktop" |
desktop (1920x1080), mobile (390x844), tablet (820x1180), or custom. |
customWidth |
integer | 1280 |
Used when viewport is custom. |
customHeight |
integer | 800 |
Used when viewport is custom. |
fullPage |
boolean | true |
Capture the full scrollable page instead of just the viewport. |
darkMode |
boolean | false |
Emulate prefers-color-scheme: dark before capturing. |
waitForSelector |
string | — | CSS selector to wait for before capturing, with a 10s timeout fallback. |
waitMs |
integer | 1000 |
Extra wait after navigation completes, in milliseconds. |
quality |
integer | 85 |
JPG/WebP quality (1-100). Ignored for PNG and PDF. |
maxItems |
integer | — | Safety cap on how many URLs to capture in this run. Leave blank to capture every URL in the list. |
PDF example
{
"urls": ["https://example.com/invoice/2026-08-01"],
"format": "pdf"
}
Mobile, dark mode example
{
"urls": ["https://example.com/"],
"format": "jpg",
"viewport": "mobile",
"darkMode": true
}
Bulk Screenshot & PDF Generator Output Fields
{
"url": "https://example.com/",
"format": "png",
"kvsKey": "b559c7edd3fb67374c1a25e739cdd7edd1d79949-png",
"sizeBytes": 22134,
"viewport": { "width": 1920, "height": 1080, "preset": "desktop" },
"capturedAt": "2026-08-04T02:53:13.724Z",
"status": "success",
"errorMsg": null,
"finalUrl": "https://example.com/",
"title": "Example Domain",
"loadTimeMs": 1329
}
| Field | Type | Description |
|---|---|---|
url |
string | Target URL that was captured |
format |
string | Output format: png, jpg, webp, or pdf |
kvsKey |
string | Key in the run's default key-value store holding the binary. null if the capture failed. |
sizeBytes |
number | Binary size in bytes |
viewport |
object | Viewport used: width, height, preset |
capturedAt |
string | ISO-8601 timestamp when the capture completed |
status |
string | success or error |
errorMsg |
string | Error message if the capture failed, otherwise null |
finalUrl |
string | Final URL after redirects |
title |
string | Page title at capture time |
loadTimeMs |
number | Milliseconds from navigation start to capture |
Fetch the binary itself from the run's key-value store using kvsKey — the dataset row is metadata, the KVS entry is the actual PNG/JPG/WebP/PDF file.
Resuming a large crawl
Every run emits a resumeCursor in its Output. If a large crawl stops before it finishes — because it hit maxItems, your spend cap (maxTotalChargeUsd), or was aborted — start a new run with the same input plus that resumeCursor to continue from where it left off. The crawl resumes from the queued work the previous run didn't reach.
- You are not re-charged for records the earlier run already delivered.
- Resume within your account's run-retention window — on the free tier, roughly your 10 most recent runs. Once the source run is pruned, its
resumeCursoris no longer valid. resumeCursoris opaque — supply it unmodified.
FAQ
How do I convert a URL to PDF in bulk?
Set format to "pdf" and pass your URL list in urls. Each URL gets its own PDF in the key-value store and a matching dataset row with the kvsKey to fetch it.
Is there a bulk screenshot API on Apify?
Yes — this actor. Pass a list of URLs and pick a format; the Apify API returns one dataset row per URL with a kvsKey pointing at the captured file, so you can script it into any pipeline that speaks HTTP.
What happens if a URL fails to load?
It still gets a dataset row, with status: "error" and an errorMsg describing what went wrong. Nothing is silently dropped — you always get one row per input URL.
Can I capture mobile screenshots?
Set viewport to "mobile" for a 390x844 viewport, or "custom" with your own customWidth/customHeight.
Do I need to set anything up before running it?
No. Point it at a URL list and run it — the capture, formatting, and storage are all handled for you.
Need More Features?
Need a different output format, a per-URL viewport, or something else entirely? File an issue or get in touch.
Why Use Bulk Screenshot & PDF Generator?
- Actually bulk — one run, one URL list, one format decision. No looping single-URL calls yourself.
- PDF included — most screenshot actors stop at PNG. This one prints to PDF in the same code path, so you don't need a second tool for invoices, contracts, or archival captures.
- Nothing gets lost — every URL in your list produces exactly one dataset row, success or failure, so a partial run never leaves you guessing which URLs didn't make it.