L logiover
data · Jul 9, 2026 · 7 min read

How to Capture Bulk Website Screenshots at Scale in 2026

Capture full-page or viewport screenshots of hundreds of URLs with headless Chromium — desktop, mobile and tablet profiles, cookie auto-dismiss, PNG or JPEG.

Taking one screenshot is trivial. Taking screenshots of three hundred URLs — full-page, on the right device profile, with cookie banners dismissed and lazy-loaded images actually loaded — is a real engineering job. The naive approaches all fall over: a simple HTTP fetch gives you raw HTML, not a rendered image; a single Playwright script chokes on consent overlays and infinite-scroll pages; and browser extensions don’t scale past a handful of tabs. This guide covers how bulk screenshot capture actually works with real headless Chromium, and how to get a clean, downloadable image plus a machine-readable manifest for every URL in a list.

What’s worth capturing

Unlike a data scraper, the primary output here is the image file itself — but each capture also produces one manifest row so you can automate the pipeline. Per URL you get:

  • The image — a PNG or JPEG saved to Apify’s key-value store, reachable at a permanent screenshotUrl you can download or share.
  • screenshotUrl — the stable public download link to that image.
  • pageTitle — the page’s HTML <title> tag, so you can label captures without opening them.
  • viewportWidth / viewportHeight — the exact viewport used for the shot.
  • fullPage — whether the capture was a full scrollable page or just the visible fold.
  • formatpng or jpeg.
  • fileSize — the image size in bytes, useful for budgeting storage.
  • capturedAt — an ISO 8601 timestamp of when the shot was taken.

The manifest is what turns this from a screenshot tool into an automation primitive: you can export the whole set to JSON, CSV, Excel or XML, join it to your source URL list, and drive downstream steps off the screenshotUrl and capturedAt fields.

How the capture actually works

Every page is rendered in real headless Chromium via Playwright — not an HTTP fetch, not a lightweight HTML renderer. That matters because modern sites are JavaScript apps: the content you want to photograph is painted by the browser after load. A real Chromium instance runs the page’s JavaScript, so single-page apps, dynamic dashboards and lazy-loaded images look exactly as they would in a normal browser.

The input is a list of URLs plus a handful of capture options. A run that grabs full-page desktop PNGs of a few homepages looks like this:

{
  "startUrls": [
    { "url": "https://apify.com" },
    { "url": "https://github.com" },
    { "url": "https://vercel.com" }
  ],
  "deviceProfile": "desktop",
  "fullPage": true,
  "format": "png",
  "waitForTimeout": 3000,
  "maxScreenshots": 100
}

There are three built-in device profiles — Desktop (1920×1080), Mobile (iPhone 15, 390×844) and Tablet (iPad Pro, 1024×1366) — plus a custom profile where you set viewportWidth and viewportHeight yourself. Setting deviceProfile to mobile uses the iPhone 15 viewport and user-agent, so you photograph the actual responsive layout, not a shrunk desktop page.

Before each shot, the actor does two things a naive script forgets. It auto-dismisses cookie banners by clicking the “Accept” control on consent pop-ups, so your screenshots aren’t buried under a GDPR overlay. And it scrolls the page to trigger lazy-loaded and infinite-scroll content, so images that only load on scroll are actually present when the capture fires. The waitForTimeout field (default 3000 ms) adds extra settle time after load — bump it to 5000–8000 ms for heavy JavaScript apps that keep rendering after the initial paint.

Open the Bulk Website Screenshot Capture actor on Apify — paste a URL list, get back a permanent PNG or JPEG per page plus a manifest of titles, sizes and timestamps. Real headless Chromium, no API key, no per-site setup.

The access reality

Because this is a real browser, the friction isn’t parsing — it’s rendering cost and page defenses. A few things to plan for:

  • Cost scales per image. Each URL is one capture and one manifest row. The maxScreenshots field (default 100, ceiling 1,000) is a hard cost guardrail: it caps the run so a huge input list can’t run away with your budget. For very large lists, split them across multiple runs or schedule them.
  • File sizes are real. A full-page PNG of a long marketing page can be several megabytes. Each screenshot is typically ~1–5 MB depending on page length and format. If you don’t need lossless quality, switch format to jpeg and drop quality to 60–70 for much smaller files.
  • Geo-restricted or rate-limited pages need a proxy. The actor supports Apify Proxy; for pages that block datacenter IPs or serve region-specific content, point proxyConfiguration at a residential group:
{
  "startUrls": [{ "url": "https://example.com" }],
  "deviceProfile": "custom",
  "viewportWidth": 1440,
  "viewportHeight": 900,
  "fullPage": true,
  "waitForTimeout": 8000,
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
  • Login-gated pages are out of scope by default. The actor captures publicly accessible URLs. Photographing pages behind authentication would require supplying session cookies.

Example output

One manifest row per screenshot:

{
  "url": "https://apify.com",
  "screenshotUrl": "https://api.apify.com/v2/key-value-stores/xxxxxxxx/records/screenshot_1.png",
  "pageTitle": "Apify — Full-stack web scraping and data extraction platform",
  "viewportWidth": "1920",
  "viewportHeight": "1080",
  "fullPage": "true",
  "format": "png",
  "fileSize": "1240523",
  "capturedAt": "2026-07-06T12:00:00.000Z"
}

The images live in the key-value store; download an individual one from its screenshotUrl, or pull the whole set through the Apify API.

Typical use cases

  • Competitive analysis & design inspiration — capture 50 competitor homepages, pricing pages and product screens in minutes for a swipe file or design review.
  • Visual regression testing & QA — run the same production URL list on a schedule and compare shots side-by-side to catch layout breaks before customers report them.
  • Website archiving & compliance — archive pages as timestamped, full-page PNGs for regulatory filings, trademark disputes or historical records where the exact rendered state matters.
  • Pre-purchase & pre-redesign audits — document the “before” state of a client site with pixel-perfect, dated screenshots before a project starts.
  • Portfolio & showcase creation — freelancers and agencies snapshot finished client work before the sites change or disappear.
  • Responsive checks — capture the same URLs on desktop, mobile and tablet profiles to verify a responsive layout in one pass.

Build-it-yourself vs. managed

You can absolutely stand up your own Playwright fleet. The cost of doing so is where the trade-off lives:

  • The browser infrastructure — provisioning headless Chromium, managing memory (full-page captures of long pages are memory-hungry), and keeping browsers from leaking across a big URL list.
  • The rendering edge cases — the cookie-banner clicker, the lazy-load scroll routine, the settle-time tuning per page type. These are the parts that separate “it works on example.com” from “it works on 300 real sites.”
  • Storage and permanent URLs — somewhere to put thousands of multi-megabyte images with stable, shareable links.
  • Proxy plumbing for geo-restricted targets.

The managed actor solves all of that and runs on pay-per-result pricing — you pay per screenshot captured, maxScreenshots keeps a run’s cost bounded and predictable, and the images come with permanent key-value-store URLs out of the box. For most teams the win is not paying for idle browser VMs between capture jobs.

Common pitfalls

Gotchas specific to bulk screenshot capture:

  • Full-page captures of infinite-scroll pages can balloon. A page that lazy-loads forever produces a giant image. Where you only need the fold, set fullPage to false.
  • waitForTimeout is a floor, not a guarantee. Heavy dashboards may still be animating at 3000 ms. If shots look half-rendered, raise it toward 8000 ms rather than assuming the page is broken.
  • JPEG quality is ignored for PNG. The quality field only applies when format is jpeg; setting it alongside png does nothing.
  • Image CDN URLs inside pages are not your screenshot URL. The stable download link is the screenshotUrl in the manifest — the images referenced inside the page itself may rotate.
  • The 1,000-screenshot ceiling is per run. For a 5,000-URL archive, chunk the list and schedule the runs rather than expecting one job to do it all.
  • Mobile profile changes both viewport and user-agent. Some sites serve a different page to iPhone user-agents — that’s the point, but don’t be surprised when the mobile shot differs structurally from desktop.

Wrapping up

Bulk screenshot capture is one of those tasks that looks like a one-liner and turns into a rendering-infrastructure project the moment you point it at real websites. If you need a handful of shots once, a local Playwright script is fine. If you need hundreds of full-page captures across device profiles, on a schedule, with cookie banners handled and permanent download URLs, the managed actor does that today.

Run the Bulk Website Screenshot Capture actor on Apify — one run returns a full-page or viewport PNG/JPEG per URL across desktop, mobile or tablet, plus a manifest of titles, file sizes and timestamps. No API key, no login. Export the manifest to JSON, CSV, Excel or XML. Start on Apify’s free monthly credit.

Related guides