Keyword: batch screenshot API · By SnapshotFlow team · Updated July 3, 2026

Batch Screenshot API: How to Capture Multiple URLs in One Request

A release report, link preview service, or website inventory rarely needs one screenshot. It needs the same capture settings applied to a list of pages, with clear results for each URL. SnapshotFlow's batch screenshot API accepts up to 10 URLs in one request, runs captures through its browser pool, and returns one result per input.

Why Batch Capture Matters in 2026

Browser automation has moved from occasional test scripts into scheduled services and agent workflows. In March 2026, Cloudflare raised its paid Browser Rendering REST limit from 3 to 10 requests per second. Google followed in May with new Chrome tooling for agent-driven web development and automated debugging.

Those releases do not measure keyword volume. They provide current evidence that vendors are investing in higher-throughput browser work. A batch endpoint helps when your application needs several consistent outputs but does not need a programmable browser session.

  • Create page thumbnails for a sitemap, CMS, or client portal.
  • Capture a fixed group of public pages for a release report.
  • Generate visual evidence for a scheduled website inventory.
  • Capture representative pages for a release report, then use separate /diff calls for pages that need pixel-level comparison.

What POST /batch Does

Send a JSON object with a urls array and one shared set of capture options. SnapshotFlow validates the URLs first, then processes valid targets in parallel up to the browser pool's available capacity.

FieldAccepted valueDefault
urls1 to 10 public HTTP or HTTPS URLsRequired
formatpng, jpeg, webp, or pdfpng
width100 to 3840 pixels1280
height100 to 2160 pixels800
quality1 to 100; useful for JPEG and WebP80
full_pageBooleanfalse
response_typebase64, paths, or image_urlsbase64
Shared settings are the key constraint. Every URL in one batch uses the same format, viewport, quality, and full_page value. Put mobile and desktop captures in separate batches. The current endpoint does not accept per-URL cookies, selectors, delays, or headers.

Step 1: Send Your First Batch with cURL

Start with three public URLs and response_type=base64. This response type is portable because each successful result contains its image data.

curl -X POST "https://api.snapshotflow.com/batch" \
  -H "X-Api-Key: $SNAPSHOTFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "urls": [
      "https://example.com/",
      "https://www.iana.org/help/example-domains",
      "https://snapshotflow.com/docs"
    ],
    "format": "webp",
    "quality": 80,
    "width": 1440,
    "height": 900,
    "full_page": false,
    "response_type": "base64"
  }' \
  -o batch.json

The endpoint returns JSON rather than a multipart archive. That makes partial failures visible and lets your application decide which images to retry.

Step 2: Read Every Result

A successful response includes total and a results array. Each successful base64 item carries the normalized URL, output format, cache status, and a data URL.

{
  "total": 3,
  "results": [
    {
      "url": "https://example.com/",
      "format": "webp",
      "cached": false,
      "image": "data:image/webp;base64,UklGR..."
    },
    {
      "url": "https://www.iana.org/help/example-domains",
      "format": "webp",
      "cached": true,
      "image": "data:image/webp;base64,UklGR..."
    },
    {
      "url": "https://snapshotflow.com/docs",
      "format": "webp",
      "cached": false,
      "image": "data:image/webp;base64,UklGR..."
    }
  ]
}

Base64 encodes each three-byte group as four characters, as defined by RFC 4648 section 4. Budget about one-third more payload than the binary files, plus JSON overhead. Choose WebP or JPEG when response size matters, and avoid full-page images unless the workflow needs the entire document.

Current output note: use base64 when you need image data in the response. paths exposes storage-local paths, while the current image_urls branch returns result metadata without a public image URL.

Step 3: Save a Batch with the Node.js SDK

The official SnapshotFlow Node.js SDK exposes the same operation as client.batch(). The SDK converts camelCase options to the API request shape.

import { mkdir, writeFile } from "node:fs/promises";
import { SnapshotFlow } from "snapshotflow";

const client = new SnapshotFlow({
  apiKey: process.env.SNAPSHOTFLOW_API_KEY!,
});

const batch = await client.batch({
  urls: [
    "https://example.com/",
    "https://www.iana.org/help/example-domains",
    "https://snapshotflow.com/docs",
  ],
  format: "webp",
  quality: 80,
  width: 1440,
  height: 900,
  responseType: "base64",
});

await mkdir("captures", { recursive: true });

for (const [index, item] of batch.results.entries()) {
  if (item.error) {
    console.error(`${item.url}: ${item.error}`);
    continue;
  }

  if (!item.image) {
    console.error(`${item.url}: response did not include image data`);
    continue;
  }

  const comma = item.image.indexOf(",");
  const bytes = Buffer.from(item.image.slice(comma + 1), "base64");
  await writeFile(`captures/${index + 1}.webp`, bytes);
}

Do not treat an HTTP 200 response as proof that every page rendered. Inspect item.error and item.image for each entry.

Step 4: Scale Beyond 10 URLs

Split larger jobs into groups of 10. Submit groups in sequence first. Add limited group concurrency only after you have measured response size, timeout behavior, and account limits.

function chunks<T>(items: T[], size: number): T[][] {
  const groups: T[][] = [];
  for (let i = 0; i < items.length; i += size) {
    groups.push(items.slice(i, i + size));
  }
  return groups;
}

const failed: string[] = [];

for (const urls of chunks(allUrls, 10)) {
  const batch = await client.batch({
    urls,
    format: "jpeg",
    quality: 75,
    width: 1280,
    height: 800,
    responseType: "base64",
  });

  for (const item of batch.results) {
    if (item.error) failed.push(item.url);
    // Save or upload item.image here.
  }
}

console.log({ failed });

This loop keeps only one batch response in memory. Upload or write each decoded image before requesting the next group. A list of 1,000 base64 screenshots can exhaust a Node process if you retain every payload.

Caching and Deterministic Captures

SnapshotFlow builds a cache key from the URL and capture options. Repeating the same item with the same settings can return cached: true; cache hits do not consume another screenshot quota unit. Change the width, height, format, quality, or full-page setting and the request produces a different cache key.

Pin every option you care about. Browser rendering can differ across operating systems, browser versions, fonts, and settings. The Playwright visual comparison guide gives the same operational warning for screenshot baselines. A hosted API centralizes the browser environment, but your application should still record capture settings beside each output.

  • Normalize and deduplicate URLs before submission.
  • Set explicit width, height, format, and full-page behavior.
  • Use one batch per viewport or output policy.
  • Store the source URL and capture options with the image.

Handle Validation and Capture Failures Differently

The endpoint has two failure layers. URL validation happens before browsers start. Capture failures happen per item.

FailureObserved behaviorRecommended action
Empty list or more than 10 URLsHTTP 400 with VALIDATION_ERRORFix the request; do not retry unchanged.
Malformed or private-network URLThe request fails during upfront URL validationRemove or correct the URL. Use a self-hosted deployment for internal targets.
Navigation or rendering failureThe affected result contains error; other items can succeedRetry only failed URLs with a capped backoff.
Quota exhausted for an itemThe item contains error: "QUOTA_EXCEEDED"Stop new groups and review quota before retrying.
Rate limit or server errorThe SDK can retry 429, 5xx, and network errorsKeep retries bounded and inspect the final response.

The current batch route claims one quota unit before each uncached render. If rendering fails after that claim, the request path does not refund it. Keep retries capped and stop the queue when repeated failures point to a persistent target problem.

The SSRF guard blocks loopback, private, and link-local targets on the hosted service. For a staging site behind a VPN or firewall, follow the authenticated and internal page guidance and run SnapshotFlow inside the network.

Choose the Endpoint That Matches the Job

JobUseReason
1 to 10 URLs with shared settingsPOST /batchOne request and one result array.
One URL with cookies, selectors, headers, or scriptsGET /screenshotThe single endpoint exposes the full capture option set.
Return immediately and receive a webhookGET /screenshot?async=trueThe batch endpoint is synchronous.
Compare two rendered pagesGET /diffReturns changed pixels, percentage, and an optional diff image.

Read the batch endpoint reference for the request schema. If you need one full-page capture before building a list workflow, start with the Screenshot API quick start.

Production Checklist

  • Keep each request between one and 10 URLs.
  • Group URLs by viewport and output settings.
  • Use base64 when the response must contain portable image data.
  • Inspect every result for error before saving images.
  • Retry failed URLs, not the entire successful batch.
  • Decode and persist each group before loading the next one.
  • Record source URL, capture options, cache status, and capture time in your application.

Batch Screenshot API FAQ

How many URLs can SnapshotFlow capture in one batch?

POST /batch accepts between one and 10 URLs. Split a larger input list into groups of 10.

Can each URL use different screenshot settings?

No. One batch shares format, quality, width, height, full_page, and response_type across every URL. Use separate batches when targets need different settings.

Does one failed capture fail the entire batch?

Navigation and rendering failures appear on the affected result while other items can succeed. URL validation runs before capture, so one malformed or blocked URL rejects the request before rendering starts.

Is the batch endpoint asynchronous?

No. POST /batch returns after its items finish. Use asynchronous single captures with GET /screenshot, async=true, and a webhook when a workflow must return immediately.

Sources

Test One Batch Before You Build the Queue

Create an API key, send two or three representative URLs, and measure the response your application will store. Then add chunking and retries around observed behavior.