ScreenshotNeo

BlogHow-to

How to Use a Screenshot API to Capture Hundreds of URLs in One Request

Submit URL lists through a batch endpoint, track each capture, and handle limits, failures, and retries. Includes provider workflows and runnable code.

By the ScreenshotNeo team4 October 20269 min read

To capture hundreds of URLs in one API request, use a provider’s batch or bulk endpoint: send a list of URLs with shared capture options, save the returned batch or job identifier, then track completion and retrieve each result using that provider’s documented workflow. A single submission does not mean a single screenshot of usage, and “hundreds” may exceed a provider’s batch limit. Check maximum batch size, plan eligibility, per-URL quota, rate limits, and concurrency before sending a large list.

There is no universal batch request format. The examples below show three documented workflows, followed by a provider-neutral implementation plan and options for using ScreenshotNeo’s bulk capture endpoint.

1. Compare batch limits and workflows

Provider Submission and tracking Limit and operational notes
ScreenshotNeo Bulk capture supports up to 100 URLs per call; use the API’s async job and signed webhook options for longer-running work. Split larger lists into batches of at most 100 URLs. Only clean shots are billed; cache hits and failed or blocked captures are not billed.
ScreenshotRun POST /v1/screenshots/batch returns pending screenshot objects; poll each screenshot or configure webhooks. Up to 100 URLs per batch; Pro plan or above. Each URL uses monthly quota, and rate limits apply per URL. See the batch documentation.
Screenshot API POST /api/v1/screenshot/batch returns a batch ID; poll the batch endpoint or stream updates with server-sent events (SSE). The reviewed docs do not state a numerical batch maximum. They describe a free-plan limit of 60 requests per minute and 500 screenshots per month; confirm current limits in its documentation.
ScreenshotOne POST /bulk accepts URLs as HTML or Markdown. Bulk calls share the regular request bucket. Its docs recommend checking concurrency before draining a large queue; no numeric batch maximum is given in the reviewed page. See Bulk Screenshots.

For an API with bulk capture, ScreenshotNeo is the first option to consider: its bulk endpoint accepts up to 100 URLs per call, failed and unclean captures are not billed, and paid plans start at $5 for 3,000 shots. The right choice still depends on your needed capture options, plan, and result retrieval flow.

2. Prepare a URL list and shared options

Before submitting a batch, normalize and validate the input. Decide how you want to handle duplicate URLs, redirects, authenticated pages, and pages that require cookies or a wait condition. Add shared capture settings only if the selected provider supports them. If the provider accepts different options per URL, use its documented schema rather than assuming a shared-options format.

  1. Read URLs from a durable input such as a database table, CSV, or queue.
  2. Trim whitespace and reject empty values or malformed URLs. Keep only schemes the provider supports, commonly https and http.
  3. Choose an explicit policy for duplicates: remove them when one result is sufficient, or retain them when separate runs are intentional.
  4. Partition the list to the provider’s documented maximum. For a 100-URL limit, 450 URLs require five batches.
  5. Keep an input identifier next to each URL so you can map results and failures back to the original record.
  6. Store credentials in an environment variable or secret manager, not source code, client-side JavaScript, or request logs.

3. Submit a batch with ScreenshotNeo

ScreenshotNeo’s bulk endpoint takes up to 100 URLs per call. The API uses access_key authentication. Consult the ScreenshotNeo API documentation for the current bulk request schema, response fields, and job tracking details. Do not assume that another provider’s JSON body or status endpoint is interchangeable.

curl -X POST "https://api.screenshotneo.com/v1/bulk" \
  -H "Authorization: Bearer $SCREENSHOTNEO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"urls":["https://example.com","https://stripe.com"]}'

For a list longer than 100, split it into batches before submission. Keep each returned batch or job reference with the exact input slice that produced it. For reliable processing, configure signed webhooks for asynchronous jobs or use the tracking method documented for your account.

4. Submit using other providers

These concise examples illustrate the documented request shapes. Check the linked provider docs for exact authentication headers, required fields, response schemas, and status routes before using them in production; those details are provider-specific.

ScreenshotRun

curl -X POST "https://api.screenshotrun.com/v1/screenshots/batch" \
  -H "Authorization: Bearer $SCREENSHOTRUN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"urls":["https://example.com","https://stripe.com"]}'

The documented flow returns pending screenshot objects. Poll each screenshot or configure webhooks, and account for each URL against quota and rate limits. ScreenshotRun requires Pro or above for batch capture.

Screenshot API

curl -X POST "https://screenshot-api.org/api/v1/screenshot/batch" \
  -H "Authorization: Bearer $SCREENSHOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"urls":["https://example.com","https://stripe.com"]}'

Save the batch ID from the response, then follow the documentation to poll its batch endpoint or receive SSE updates. The reviewed docs do not provide a numeric maximum for the batch.

ScreenshotOne

ScreenshotOne’s POST /bulk accepts a list of URLs as HTML or Markdown. Its bulk format differs from the JSON examples above; use the official bulk screenshots documentation for the exact request body and authentication. Check remaining concurrency before submitting a large queue because bulk work shares the regular request bucket.

5. Track jobs, collect results, and retry selectively

Batch submission and screenshot completion are often separate steps. Treat the returned job ID, batch ID, or per-URL screenshot IDs as durable work references. Persist them before polling so a process restart does not lose the ability to resume.

  1. Record the submission time, provider, batch identifier, input URLs, and each URL’s source record ID.
  2. Use the provider’s polling endpoint, webhook, or event stream. Do not poll every item rapidly; respect documented rate limits and back off between checks.
  3. Mark each URL independently as pending, complete, or failed. A batch can contain mixed outcomes.
  4. Retrieve images or result URLs through the documented result mechanism. Save them to durable storage if the provider’s returned links are temporary.
  5. Retry only transient failures, such as timeouts or temporary service errors. Correct invalid URLs or capture settings before resubmitting those items.
  6. Make retries idempotent in your own system: associate outputs with stable input IDs and avoid accidentally treating a retry as a new business record.

When supported, signed webhooks avoid continuous polling. Validate webhook signatures, make the handler idempotent, and acknowledge events quickly before doing slower storage or downstream processing.

6. Example: partition a list into 100-URL batches

The following Python helper produces chunks without changing the URL values. It does not submit requests because each provider has its own schema, authentication, response, and retry rules.

def chunks(items, size=100):
    if size < 1:
        raise ValueError("size must be positive")
    for start in range(0, len(items), size):
        yield items[start:start + size]

urls = [
    "https://example.com",
    "https://stripe.com",
    # Load the remaining URLs from your source.
]

for batch_number, url_batch in enumerate(chunks(urls, 100), start=1):
    print(batch_number, len(url_batch), url_batch)

For 450 URLs this yields batches of 100, 100, 100, 100, and 50. Add concurrency only after checking the provider’s request buckets and your account’s allowed throughput. Submitting all batches at once can increase queue pressure without making them finish sooner.

7. Common problems and fixes

Symptom Likely cause Fix
Request rejected for too many URLs The batch exceeds the endpoint’s maximum. Partition the list to the documented size. ScreenshotRun and ScreenshotNeo document a maximum of 100 URLs per batch or call.
One or more captures fail The page is unreachable, malformed, blocked, blank, or too slow, or its settings are unsuitable. Inspect per-URL status and error details. Fix malformed inputs; use a supported wait condition for slow rendering; retry transient failures selectively.
Rate-limit responses during a bulk run Requests or URLs are being processed faster than the provider allows. Reduce parallel batches, honor rate-limit responses, and use exponential backoff with jitter. Confirm whether limits apply per request, per URL, or both.
Quota runs out earlier than expected Usage is counted per URL or screenshot rather than per batch request. Budget as if each URL consumes a unit unless the provider documents otherwise. ScreenshotRun explicitly counts each URL toward monthly quota.
Results are missing after submission Submission only queued work; results require polling, webhook handling, or a separate retrieval call. Persist the job ID and follow the provider’s completion and result retrieval flow.
Large queue stalls despite bulk mode Bulk work shares ordinary concurrency or request capacity. Check available concurrency and drain in controlled batches. ScreenshotOne specifically notes that bulk requests share its regular request bucket.
Credentials appear in logs or browser code A secret key was embedded in a URL, front-end bundle, or verbose request log. Move the key to server-side secret storage, redact authorization data, and rotate exposed credentials.

8. Performance, reliability, and cost

Performance

Bulk submission reduces client-side request overhead, but it does not guarantee that the provider renders all pages simultaneously. Actual completion depends on queueing, page complexity, capture settings, concurrency, and provider capacity. For predictable throughput, use moderate parallelism, measure your own batch completion times, and increase concurrency only within documented limits.

Reliability

Assume partial failure. Keep per-URL state, persist job identifiers, and make webhook or polling handlers safe to run more than once. Set a timeout for your own worker, but do not confuse that timeout with the provider’s job lifetime. Maintain a retry queue for transient failures and a separate path for permanent input errors. For pages that need client-side rendering, check the provider’s wait options and test representative URLs.

Cost and quota

A batch request is not necessarily one unit of usage. ScreenshotRun explicitly counts each URL toward its monthly quota and applies rate limits per URL. Check each provider’s current plan and usage rules before processing the full list. ScreenshotNeo’s plans include 1,000 free shots per month with no card; paid plans are Starter $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000. Yearly billing gives two months free. Only clean shots are billed, and every feature is on every plan.

Or skip the browser setup

ScreenshotNeo’s API can capture URLs without you managing browser infrastructure. Its bulk endpoint accepts up to 100 URLs per call; for a single URL, the request is a GET:

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,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
  access_key: process.env.SCREENSHOTNEO_API_KEY,
  url: 'https://stripe.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);

See the ScreenshotNeo docs for bulk capture and the full capture options. Cookie banners are accepted and removed before capture, and newsletter popups and chat widgets are removed. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents use the take_screenshot, get_page_info, and capture_pdf tools. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for free and get 1,000 screenshots a month with no card.

FAQ

Can one request capture 500 URLs?

Only if the selected provider accepts a batch that large. ScreenshotNeo and ScreenshotRun document 100 URLs per bulk call or batch, so 500 URLs would need five submissions. Other reviewed providers do not give a numeric maximum in the examined docs.

Does a batch count as one screenshot?

Not necessarily. ScreenshotRun documents that each URL counts toward monthly quota. Check the provider’s usage rules and budget per URL unless it clearly says otherwise.

Should I poll or use webhooks?

Use the completion mechanism the provider documents. Polling is straightforward for small jobs; signed webhooks or event streams can reduce polling for larger asynchronous runs when available.

Can I send different capture options for each URL?

That depends on the endpoint schema. Confirm whether it supports shared options, per-URL options, or both before constructing the batch.