Batch Screenshots

The batch endpoint lets you capture multiple screenshots in a single request, with support for both synchronous and asynchronous processing. To send a batch from a workflow tool, see the Pipedream batch step.

Endpoint

POST https://api.renderscreenshot.com/v1/batch

Authentication

Include your API key in the Authorization header:

Authorization: Bearer rs_live_xxxxx

Simple Batch Request

Apply the same options to all URLs:

{
  "urls": [
    "https://example1.com",
    "https://example2.com",
    "https://example3.com"
  ],
  "options": {
    "preset": "og_card",
    "block": { "ads": true }
  }
}
Parameter Type Required Description
urls array Yes* List of URLs to screenshot (*or use requests)
options object No Options applied to all URLs

How many URLs of one batch render at the same time is set by your plan, not by the request. See rate limits.

Advanced Batch Request

Specify different options per URL:

{
  "requests": [
    { "url": "https://example1.com", "preset": "og_card" },
    { "url": "https://example2.com", "preset": "full_page" },
    { "url": "https://example3.com", "viewport": { "width": 1920 } }
  ],
  "webhook": {
    "url": "https://your-server.com/webhook"
  }
}
Parameter Type Required Description
requests array Yes* Array of request objects with individual options
webhook object No Webhook configuration for async processing

Sync vs Async Processing

Synchronous (≤10 URLs without webhook): - Request blocks until all screenshots complete - Returns full results in response

Asynchronous (>10 URLs or webhook specified): - Returns immediately with job ID - Poll GET /v1/batch/:id for status - Or receive webhook on completion

Synchronous Response

{
  "id": "batch_abc123",
  "status": "completed",
  "total": 3,
  "completed": 2,
  "failed": 1,
  "credits_used": 2,
  "started_at": "2024-01-18T12:00:00Z",
  "completed_at": "2024-01-18T12:00:04Z",
  "results": [
    {
      "position": 0,
      "url": "https://example1.com",
      "status": "completed",
      "image": {
        "image_url": "https://cdn.renderscreenshot.com/abc.png",
        "width": 1200,
        "height": 630,
        "size": 48213,
        "format": "png"
      },
      "error": null,
      "response_time_ms": 1840
    },
    {
      "position": 1,
      "url": "https://example2.com",
      "status": "completed",
      "image": {
        "image_url": "https://cdn.renderscreenshot.com/def.png",
        "width": 1280,
        "height": 4500,
        "size": 312988,
        "format": "png"
      },
      "error": null,
      "response_time_ms": 3120
    },
    {
      "position": 2,
      "url": "https://example3.com",
      "status": "failed",
      "image": null,
      "error": "Page failed to load within 30 seconds",
      "response_time_ms": null
    }
  ],
  "usage": {
    "credits": 2,
    "remaining": 9997
  }
}

The counts (total, completed, failed) are top-level fields. Each item in results has these fields:

Field Type Description
position integer Index of the URL in your request
url string The URL that was captured
status string completed or failed
image object \ null
error string \ null
response_time_ms integer \ null

Asynchronous Response

Initial response (HTTP 202):

{
  "id": "batch_abc123",
  "status": "processing",
  "total": 50,
  "progress": 0,
  "message": "Batch queued for processing"
}

Poll for status:

GET /v1/batch/batch_abc123

While the batch is still running, the response has the counts and progress:

{
  "id": "batch_abc123",
  "status": "processing",
  "total": 50,
  "completed": 31,
  "failed": 1,
  "progress": 64.0,
  "started_at": "2024-01-18T12:00:00Z"
}

When the batch finishes, the response has the same shape as the synchronous response.

Webhook Integration

When a webhook is configured, you'll receive a POST request on completion:

{
  "event": "batch.completed",
  "id": "batch_abc123",
  "timestamp": "2024-01-18T12:00:00Z",
  "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-item results.

See Webhooks for configuration details.

Examples

Simple Batch

curl

curl -X POST https://api.renderscreenshot.com/v1/batch \
  -H "Authorization: Bearer rs_live_xxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "urls": [
      "https://github.com",
      "https://stripe.com",
      "https://linear.app"
    ],
    "options": {
      "preset": "og_card"
    }
  }'

Java

import com.renderscreenshot.sdk.Client;
import com.renderscreenshot.sdk.TakeOptions;
import com.renderscreenshot.sdk.model.BatchResponse;
import com.renderscreenshot.sdk.model.BatchResult;
import java.util.Arrays;

Client client = new Client("rs_live_xxxxx");

BatchResponse results = client.batch(
    Arrays.asList("https://github.com", "https://stripe.com", "https://linear.app"),
    TakeOptions.url("").preset("og_card")
);

System.out.println("Completed: " + results.getCompleted() + "/" + results.getTotal());
for (BatchResult item : results.getResults()) {
    String url = item.isSuccess() ? item.getImage().getImageUrl() : "failed";
    System.out.println(item.getUrl() + ": " + url);
}

Node.js

import { Client, TakeOptions } from 'renderscreenshot';

const client = new Client('rs_live_xxxxx');

const results = await client.batch(
  ['https://github.com', 'https://stripe.com', 'https://linear.app'],
  TakeOptions.url('').preset('og_card')
);

console.log(`Completed: ${results.completed}/${results.total}`);
for (const item of results.results) {
  console.log(`${item.url}: ${item.status === 'completed' ? item.image?.image_url : 'failed'}`);
}

PHP

use RenderScreenshot\Client;
use RenderScreenshot\TakeOptions;

$client = new Client('rs_live_xxxxx');

$results = $client->batch(
    ['https://github.com', 'https://stripe.com', 'https://linear.app'],
    TakeOptions::url('')->preset('og_card')
);

echo "Completed: {$results['completed']}/{$results['total']}\n";
foreach ($results['results'] as $item) {
    $url = $item['status'] === 'completed' ? $item['image']['image_url'] : 'failed';
    echo "{$item['url']}: {$url}\n";
}

Python

from renderscreenshot import Client, TakeOptions

client = Client('rs_live_xxxxx')

results = client.batch(
    ['https://github.com', 'https://stripe.com', 'https://linear.app'],
    TakeOptions.url('').preset('og_card')
)

print(f"Completed: {results['completed']}/{results['total']}")
for item in results['results']:
    url = item['image']['image_url'] if item['status'] == 'completed' else 'failed'
    print(f"{item['url']}: {url}")

Ruby

require 'net/http'
require 'json'

uri = URI('https://api.renderscreenshot.com/v1/batch')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer rs_live_xxxxx'
request['Content-Type'] = 'application/json'
request.body = {
  urls: ['https://github.com', 'https://stripe.com', 'https://linear.app'],
  options: { preset: 'og_card' }
}.to_json

response = http.request(request)
results = JSON.parse(response.body)

puts "Completed: #{results['completed']}/#{results['total']}"
results['results'].each do |item|
  url = item['status'] == 'completed' ? item['image']['image_url'] : 'failed'
  puts "#{item['url']}: #{url}"
end

Advanced Batch with Per-URL Options

Java

import com.renderscreenshot.sdk.Client;
import com.renderscreenshot.sdk.TakeOptions;
import com.renderscreenshot.sdk.model.BatchResponse;
import java.util.Arrays;

Client client = new Client("rs_live_xxxxx");

BatchResponse results = client.batchAdvanced(Arrays.asList(
    new Client.BatchRequest("https://github.com",
        TakeOptions.url("https://github.com").preset("og_card")),
    new Client.BatchRequest("https://stripe.com",
        TakeOptions.url("https://stripe.com").fullPage()),
    new Client.BatchRequest("https://linear.app",
        TakeOptions.url("https://linear.app").width(1920).darkMode())
));

Node.js

import { Client } from 'renderscreenshot';

const client = new Client('rs_live_xxxxx');

const results = await client.batch([
  { url: 'https://github.com', options: { preset: 'og_card' } },
  { url: 'https://stripe.com', options: { preset: 'full_page' } },
  { url: 'https://linear.app', options: { width: 1920, darkMode: true } },
]);

PHP

use RenderScreenshot\Client;

$client = new Client('rs_live_xxxxx');

$results = $client->batchAdvanced([
    ['url' => 'https://github.com', 'options' => ['preset' => 'og_card']],
    ['url' => 'https://stripe.com', 'options' => ['preset' => 'full_page']],
    ['url' => 'https://linear.app', 'options' => ['width' => 1920, 'dark_mode' => true]],
]);

Python

from renderscreenshot import Client

client = Client('rs_live_xxxxx')

results = client.batch([
    {'url': 'https://github.com', 'options': {'preset': 'og_card'}},
    {'url': 'https://stripe.com', 'options': {'preset': 'full_page'}},
    {'url': 'https://linear.app', 'options': {'width': 1920, 'dark_mode': True}},
])

Ruby

require 'net/http'
require 'json'

uri = URI('https://api.renderscreenshot.com/v1/batch')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer rs_live_xxxxx'
request['Content-Type'] = 'application/json'
request.body = {
  requests: [
    { url: 'https://github.com', preset: 'og_card' },
    { url: 'https://stripe.com', preset: 'full_page' },
    { url: 'https://linear.app', viewport: { width: 1920 } }
  ]
}.to_json

response = http.request(request)
results = JSON.parse(response.body)

Polling Batch Status

Java

import com.renderscreenshot.sdk.Client;
import com.renderscreenshot.sdk.TakeOptions;
import com.renderscreenshot.sdk.model.BatchResponse;
import java.util.Arrays;

Client client = new Client("rs_live_xxxxx");

// Start a batch
BatchResponse batch = client.batch(
    Arrays.asList("https://example1.com", "https://example2.com"),
    TakeOptions.url("").preset("og_card")
);

// Poll for completion
BatchResponse status = client.getBatch(batch.getId());
while ("processing".equals(status.getStatus())) {
    Thread.sleep(1000);
    status = client.getBatch(batch.getId());
    System.out.println("Progress: " + status.getCompleted() + "/" + status.getTotal());
}

Node.js

import { Client } from 'renderscreenshot';

const client = new Client('rs_live_xxxxx');

// Start a batch
const batch = await client.batch(['https://example1.com', 'https://example2.com']);

// Poll for completion
let status = await client.getBatch(batch.id);
while (status.status === 'processing') {
  await new Promise(resolve => setTimeout(resolve, 1000));
  status = await client.getBatch(batch.id);
  console.log(`Progress: ${status.completed}/${status.total}`);
}

PHP

use RenderScreenshot\Client;

$client = new Client('rs_live_xxxxx');

// Start a batch
$batch = $client->batch(['https://example1.com', 'https://example2.com']);

// Poll for completion
$status = $client->getBatch($batch['id']);
while ($status['status'] === 'processing') {
    sleep(1);
    $status = $client->getBatch($batch['id']);
    echo "Progress: {$status['completed']}/{$status['total']}\n";
}

Python

import time
from renderscreenshot import Client

client = Client('rs_live_xxxxx')

# Start a batch
batch = client.batch(['https://example1.com', 'https://example2.com'])

# Poll for completion
status = client.get_batch(batch['id'])
while status['status'] == 'processing':
    time.sleep(1)
    status = client.get_batch(batch['id'])
    print(f"Progress: {status['completed']}/{status['total']}")

Ruby

require 'net/http'
require 'json'

base_uri = 'https://api.renderscreenshot.com/v1'

# Start a batch
uri = URI("#{base_uri}/batch")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer rs_live_xxxxx'
request['Content-Type'] = 'application/json'
request.body = { urls: ['https://example1.com', 'https://example2.com'] }.to_json

response = http.request(request)
batch = JSON.parse(response.body)

# Poll for completion
loop do
  status_uri = URI("#{base_uri}/batch/#{batch['id']}")
  status_request = Net::HTTP::Get.new(status_uri)
  status_request['Authorization'] = 'Bearer rs_live_xxxxx'

  status_response = http.request(status_request)
  status = JSON.parse(status_response.body)

  puts "Progress: #{status['completed']}/#{status['total']}"
  break unless status['status'] == 'processing'

  sleep(1)
end

Rate Limits

Batch size limits vary by plan:

Plan Max batch size
Free 5
Starter 20
Growth 50
Scale 100

See Rate Limits for more details.

See Also

Was this page helpful?