A batch is one request with many URLs. RenderScreenshot captures them in parallel and returns one result per URL. You will send a list, read the results, and switch to a webhook when the list is big.
How many URLs fit in one batch depends on the plan:
| Plan | URLs per batch |
|---|---|
| Free | 5 |
| Starter | 20 |
| Growth | 50 |
| Scale | 100 |
For more URLs, send several batches. Each URL still uses one credit, and the batch needs enough credits left for every URL before it starts.
Send the list
Put the URLs in urls and the options that apply to all of them in options:
curl -X POST https://api.renderscreenshot.com/v1/batch \ -H "Authorization: Bearer $RS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "urls": [ "https://renderscreenshot.com", "https://renderscreenshot.com/pricing", "https://renderscreenshot.com/docs", "https://renderscreenshot.com/blog" ], "options": { "preset": "og_card", "block": { "cookie_banners": true } } }'
A batch of 10 URLs or fewer, without a webhook, waits until all images are done and returns the results in the response. This one took 22 seconds.
Read the results
The real response, shortened to one result:
{ "id": "batch_64b5ba827fbcc4b39f62da5e", "status": "completed", "total": 4, "completed": 4, "failed": 0, "credits_used": 4, "results": [ { "position": 0, "url": "https://renderscreenshot.com", "status": "completed", "image": { "image_url": "https://cdn.renderscreenshot.com/screenshots/.../dc31bb01ebc6.png", "width": 1200, "height": 630, "format": "png", "size": 102621 }, "error": null, "response_time_ms": 4443 } ] }
position is the index of the URL in your list. A failed item has "status": "failed", an error message, and costs no credits. Download each image_url, or store the link: it is a public CDN link, kept for the cache time of the request (24 hours by default).
Node.js
const response = await fetch('https://api.renderscreenshot.com/v1/batch', { method: 'POST', headers: { Authorization: `Bearer ${process.env.RS_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ urls, options: { preset: 'og_card', block: { cookie_banners: true } } }), }); const batch = await response.json(); for (const item of batch.results) { if (item.status === 'completed') { console.log(item.url, item.image.image_url); } else { console.warn('failed', item.url, item.error); } }
Python
import os import requests response = requests.post( 'https://api.renderscreenshot.com/v1/batch', headers={'Authorization': f"Bearer {os.environ['RS_API_KEY']}"}, json={'urls': urls, 'options': {'preset': 'og_card', 'block': {'cookie_banners': True}}}, timeout=300, ) batch = response.json() for item in batch['results']: if item['status'] == 'completed': print(item['url'], item['image']['image_url']) else: print('failed', item['url'], item['error'])
To give one URL its own options, send requests instead of urls: a list of objects, each with its own url and options. See the batch reference.
Use a webhook for big lists
A batch with more than 10 URLs, or with a webhook, runs in the background. The API answers at once with HTTP 202 and the batch ID. Add a webhook so the API tells you when it is done:
{ "urls": ["https://example.com/1", "https://example.com/2", "..."], "options": { "preset": "og_card" }, "webhook": { "url": "https://acme.example/webhooks/renderscreenshot" } }
When the batch finishes, your endpoint receives:
{ "event": "batch.completed", "id": "batch_abc123", "data": { "summary": { "total": 50, "completed": 48, "failed": 2 }, "results_url": "https://api.renderscreenshot.com/v1/batch/batch_abc123" } }
Fetch results_url with your API key to get the per-URL results, in the same format as step 2. Without a webhook, poll GET /v1/batch/{id} every few seconds until status is completed.
To use the same endpoint for every request, set it once in Webhooks in the dashboard. The page also shows the secret you need in step 4.
Verify the webhook
Anyone can send a request to your endpoint. Check the signature before you trust it. The SDKs include a helper:
import express from 'express'; import { verifyWebhook, parseWebhook } from 'renderscreenshot'; const app = express(); // express.raw keeps the exact bytes that were signed. app.post('/webhooks/renderscreenshot', express.raw({ type: 'application/json' }), async (req, res) => { const payload = req.body.toString('utf8'); const valid = verifyWebhook(payload, req.headers['x-webhook-signature'], req.headers['x-webhook-timestamp'], process.env.WEBHOOK_SECRET); if (!valid) return res.status(401).send('Invalid signature'); res.status(200).send('OK'); // answer fast, then do the work const event = parseWebhook(payload); if (event.type === 'batch.completed') await downloadResults(event.data.results_url); });
Answer with a 2xx status within a few seconds. If your endpoint fails, the API retries the delivery. Webhook verification has Python, Ruby, PHP, Go and Java versions.
Next steps
- Capture pages on a schedule.
- Save screenshots to your bucket, so batch results land in your storage.
- Watch your credits before a big run.