Batch Screenshot a List of URLs with Webhook Delivery
Fire a list of URLs at one Rendex endpoint and let signed webhooks push each screenshot back to n8n as it finishes — no polling loop, no long-running HTTP request, no queue to babysit.
Last updated 2026-07-21
The Problem
You have a list of URLs to capture on a schedule — a competitor watchlist, every page in a sitemap, a set of customer dashboards. Looping them through a synchronous screenshot call holds an HTTP request open for 5–30 seconds per URL, so a list of 50 either times out the n8n execution or blocks the workflow for minutes. Building your own async layer means a queue, retry logic, idempotency, and a callback receiver — infrastructure that has nothing to do with the screenshots you actually want.
The Solution
Rendex exposes a first-class batch endpoint. Submit the whole URL array in one POST with shared capture defaults and a webhookUrl, get a batchId back immediately, and let Rendex push an HMAC-signed callback to your n8n Webhook node as each job completes. n8n verifies the signature, then routes the resultUrl to storage or a notification — the workflow never blocks waiting on a render.
How the Workflow Runs
Schedule
An n8n Schedule trigger fires the run (e.g. nightly at 02:00).
Read URL list
Pull the URLs from a Google Sheet, Airtable base, or a static list node.
Rendex batch
POST /v1/screenshot/batch with { urls, defaults, webhookUrl } pointing at your n8n Webhook node. Returns a batchId.
Signed callbacks
Your n8n Webhook node receives x-rendex-signature callbacks per job — verify, then store to S3 or notify Slack.
Input → Rendered Output

Rendered by Rendex
What You Need
- A Rendex API key on the Starter plan or higher — batch is a paid feature (the free tier does single renders). Starter allows 25 URLs per batch, Pro 100, Enterprise 500.
- An n8n instance with a publicly reachable Webhook node URL (Rendex must be able to POST to it from the open internet).
- A URL list source: a Google Sheets node, an Airtable node, or a static Set/Code node holding the array.
- A shared webhook secret you store in n8n credentials and use to verify the x-rendex-signature HMAC on every callback.
What This Recipe Uses
One batch request
POST /v1/screenshot/batch takes a urls array (1–500) plus a single defaults object applied to every capture — no per-URL loop.
HMAC-signed callbacks
Each job POSTs to your webhookUrl with x-rendex-signature, x-rendex-event, x-rendex-timestamp, and x-rendex-delivery-id headers. Verify before you trust the resultUrl.
Async, never blocks
The batch returns a batchId right away. Your n8n run finishes in milliseconds while Rendex renders in the background and pushes results as they land.
Built-in retries
Webhook delivery retries up to 3 times (10s timeout each) on failure, so a brief blip on your n8n endpoint will not silently drop a result.
Build It
# Submit a list of URLs in one request. Each capture inherits "defaults".
# Rendex POSTs an HMAC-signed callback to webhookUrl as each job completes.
curl -X POST https://api.rendex.dev/v1/screenshot/batch \
-H "Authorization: Bearer $RENDEX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"urls": [
"https://example.com/pricing",
"https://example.com/blog",
"https://example.com/changelog"
],
"defaults": {
"format": "png",
"fullPage": true,
"width": 1280,
"blockCookieBanners": true
},
"webhookUrl": "https://your-n8n.example.com/webhook/rendex-batch"
}'
# => { "batchId": "btc_01HX...", "jobs": [ { "jobId": "job_01..." }, ... ] }
# Batch is Starter+. Starter 25 / Pro 100 / Enterprise 500 URLs per request.// Rendex POSTs one of these to your webhookUrl per finished job, plus a
// final "batch.completed" summary. Headers carry the auth signal:
// x-rendex-event: "job.completed" | "job.failed" | "batch.completed"
// x-rendex-signature: HMAC-SHA256 over `${timestamp}.${rawBody}`
// x-rendex-timestamp: unix seconds (matches the value signed above)
// x-rendex-delivery-id: uuid (use for idempotency / dedupe)
{
"event": "job.completed",
"batchId": "btc_01HX...",
"jobId": "job_01HX...",
"status": "completed",
"resultUrl": "https://cdn.rendex.dev/r/01HX....png",
"metadata": { "url": "https://example.com/pricing", "format": "png" },
"completedAt": "2026-05-28T02:00:14.220Z"
}
// Final summary event for the whole batch:
// {
// "event": "batch.completed", "batchId": "btc_01HX...",
// "status": "completed", "totalJobs": 3,
// "completedJobs": 3, "failedJobs": 0,
// "completedAt": "2026-05-28T02:00:31.004Z"
// }// n8n Code node placed right after the Webhook node.
// Rejects forged callbacks before you store or notify on anything.
const crypto = require('crypto');
const SECRET = $env.RENDEX_WEBHOOK_SECRET; // set in n8n env / credentials
// The Webhook node must run in "raw body" mode so the bytes match what Rendex
// signed. Pull the raw string + headers off the incoming item:
const headers = $input.first().json.headers;
const rawBody = $input.first().json.body; // exact bytes as received
const signature = headers['x-rendex-signature'];
const timestamp = headers['x-rendex-timestamp'];
// Rendex signs `${timestamp}.${rawBody}` with HMAC-SHA256:
const expected = crypto
.createHmac('sha256', SECRET)
.update(`${timestamp}.${rawBody}`)
.digest('hex');
const ok =
signature &&
signature.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
if (!ok) {
throw new Error('Invalid Rendex webhook signature — rejecting callback.');
}
// Optional: reject stale callbacks (replay protection).
const ageSeconds = Math.abs(Date.now() / 1000 - Number(timestamp));
if (ageSeconds > 300) {
throw new Error('Stale Rendex webhook (>5 min) — rejecting.');
}
const payload = JSON.parse(rawBody);
return [{ json: payload }]; // -> route resultUrl to S3 / Slack / DB downstream100 free API calls/month — no credit card required. Get your API key and start building.
Reach for this workflow whenever you have more than a handful of URLs to capture and you do not want the run to block while they render. A nightly competitor watchlist, a full sitemap audit, a set of tenant dashboards you screenshot for a weekly report — all of them are lists, and lists belong in a batch. The pattern matters because synchronous calls couple your n8n execution time to the slowest page on the list; one heavy URL stalls the whole run. Batching decouples them: you submit once, n8n moves on, and each finished capture arrives as its own signed callback you can route independently to S3, Slack, or a database. The HMAC signature is the part people skip and regret — without verifying x-rendex-signature, any host that learns your webhook URL can forge job.completed payloads. Batch processing is a Starter-plan feature (the free tier is single-render); the batch size cap — 25 URLs on Starter, up to 500 on Enterprise — scales with your plan.