Node.js SDK

The official Node.js/TypeScript SDK for RenderScreenshot.

Installation

npm install renderscreenshot

Requirements

  • Node.js 20.0.0 or higher

Quick Start

import { Client, TakeOptions } from 'renderscreenshot';

const client = new Client('rs_live_xxxxx');

// Take a screenshot
const image = await client.take(
  TakeOptions.url('https://example.com').preset('og_card')
);

Client

Constructor

import { Client } from 'renderscreenshot';

const client = new Client(apiKey, options);
Parameter Type Description
apiKey string Your API key (rs_live_*)
options.baseUrl string API base URL (default: https://api.renderscreenshot.com)
options.timeout number Request timeout in ms (default: 30000)
options.signingKey string Signing key (rs_secret_*). Only needed for generateUrl()
options.publicKeyId string Public key ID (rs_pub_*). Only needed for generateUrl()
const client = new Client('rs_live_xxxxx', {
  signingKey: process.env.RS_SIGNING_KEY,    // rs_secret_...
  publicKeyId: process.env.RS_PUBLIC_KEY_ID, // rs_pub_...
});

take(), takeJson() and batch() send options as nested JSON (viewport.width, capture.mode, output.format, ...), as described in the POST /v1/screenshot reference.

Methods

take(options)

Take a screenshot and return binary data.

const image = await client.take(
  TakeOptions.url('https://example.com').preset('og_card')
);

// Save to file
import { writeFile } from 'fs/promises';
await writeFile('screenshot.png', image);

Returns: Promise<Buffer>

takeJson(options)

Take a screenshot and return JSON metadata. The SDK sends Accept: application/json, so the API returns metadata instead of image bytes.

const response = await client.takeJson(
  TakeOptions.url('https://example.com').preset('og_card')
);

console.log(response.id);             // 'req_...'
console.log(response.status);         // 'completed'
console.log(response.image?.url);     // CDN URL
console.log(response.image?.width);   // 1200
console.log(response.image?.height);  // 630
console.log(response.cache?.hit);     // true/false
console.log(response.usage?.remaining);

Returns: Promise<ScreenshotResponse>. The object is the API JSON: id, status, image (url, width, height, size, format), metadata, cache (hit, key, url, expires_at) and usage (credits, remaining). A request with a webhook returns status: 'processing' and no image.

generateUrl(options, expiresAt, credentials?)

Generate a signed URL for public embedding. Signed URLs work only with the GET render endpoint (GET /v1/screenshot). They need a public key ID (rs_pub_*) and a signing key (rs_secret_*). Your rs_live_* API key and the signing key are never put in the URL.

const client = new Client('rs_live_xxxxx', {
  signingKey: process.env.RS_SIGNING_KEY,    // rs_secret_...
  publicKeyId: process.env.RS_PUBLIC_KEY_ID, // rs_pub_...
});

const signedUrl = client.generateUrl(
  TakeOptions.url('https://example.com').preset('og_card'),
  new Date(Date.now() + 24 * 60 * 60 * 1000) // 24 hours (max 30 days)
);

// Use in HTML: <img src="${signedUrl}" />

You can also pass the credentials per call:

const signedUrl = client.generateUrl(options, expiresAt, {
  signingKey: 'rs_secret_xxxxx',
  publicKeyId: 'rs_pub_xxxxx',
});

The URL contains expires, key_id, the options as flat GET parameters (width, height, full_page, selector, format, ...) and a signature. Only options that the GET endpoint accepts are included. Use take() or takeJson() for options such as mobile(), waitFor(), waitForSelector(), network, storage and script/style injection. See Signed URLs.

Returns: string

Throws: RenderScreenshotError with code invalid_request if signingKey or publicKeyId is missing.

batch(urls, options) / batch(requests)

Process multiple screenshots in a batch.

// Simple batch
const results = await client.batch(
  ['https://example1.com', 'https://example2.com'],
  TakeOptions.url('').preset('og_card')
);

// Advanced batch with per-URL options
const results = await client.batch([
  { url: 'https://example1.com', options: { preset: 'og_card' } },
  { url: 'https://example2.com', options: { width: 1920 } },
]);

Returns: Promise<BatchResponse>

getBatch(batchId)

Get the status of a batch job.

const status = await client.getBatch('batch_abc123');
console.log(status.completed, status.total);

Returns: Promise<BatchResponse>

presets() / preset(id)

Get available presets.

const presets = await client.presets();
const ogCard = await client.preset('og_card');

devices()

Get available device presets.

const devices = await client.devices();

TakeOptions

Fluent builder for screenshot options.

Creating Options

import { TakeOptions } from 'renderscreenshot';

// From URL
const options = TakeOptions.url('https://example.com');

// From HTML
const options = TakeOptions.html('<h1>Hello World</h1>');

// From config object
const options = TakeOptions.from({ url: '...', width: 1200 });

Viewport Options

TakeOptions.url('...')
  .width(1200)           // Viewport width
  .height(630)           // Viewport height
  .scale(2)              // Device scale factor (1-3)
  .mobile()              // Enable mobile emulation

Capture Options

TakeOptions.url('...')
  .fullPage()            // Capture full scrollable page
  .element('.hero')      // Capture specific element
  .format('png')         // png, jpeg, webp, pdf
  .quality(90)           // JPEG/WebP quality (1-100)

Wait Options

TakeOptions.url('...')
  .waitFor('networkidle')      // load, networkidle, domcontentloaded
  .delay(2000)                 // Additional delay (ms)
  .waitForSelector('.loaded')  // Wait for selector
  .waitForTimeout(30)          // Max wait time (s, 1-60)

Presets & Devices

TakeOptions.url('...')
  .preset('og_card')           // Use a preset
  .device('iphone_14_pro')     // Emulate a device

Content Blocking

TakeOptions.url('...')
  .blockAds()                  // Block ad networks
  .blockTrackers()             // Block analytics
  .blockCookieBanners()        // Auto-dismiss cookie popups
  .blockChatWidgets()          // Block chat widgets
  .blockUrls(['*.ads.com/*'])  // Block URL patterns
  .blockResources(['font'])    // Block resource types

Page Modifications

TakeOptions.url('...')
  .click('#accept')            // Click an element before capture
  .hide(['.chat-widget'])      // Hide elements (visibility: hidden)
  .remove(['.promo-banner'])   // Remove elements from the DOM
  .injectStyle('body { font-size: 18px; }')   // Sent as page.styles
  .injectScript('window.scrollTo(0, 0);')     // Sent as page.scripts

These map to the page options.

Browser Emulation

TakeOptions.url('...')
  .darkMode()                  // Enable dark mode
  .reducedMotion()             // Prefer reduced motion
  .mediaType('print')          // screen or print
  .userAgent('Custom UA')      // Custom user agent
  .timezone('America/New_York')
  .locale('en-US')
  .geolocation(40.7128, -74.006)

Network Options

TakeOptions.url('...')
  .headers({ 'X-Custom': 'value' })
  .cookies([{ name: 'session', value: 'abc', domain: 'example.com' }])
  .authBasic('user', 'pass')
  .authBearer('token')
  .bypassCsp()

Cache Options

TakeOptions.url('...')
  .cacheTtl(86400)             // Cache TTL in seconds
  .cacheAvailable()            // Reuse an identical render inside the TTL (0 credits)
  .cacheRefresh()              // Force refresh

PDF Options

TakeOptions.url('...')
  .format('pdf')
  .pdfPaperSize('a4')          // a4, letter, legal, etc.
  .pdfLandscape()
  .pdfMargin('1in')
  .pdfPrintBackground()
  .pdfHeader('<div>Header</div>')
  .pdfFooter('<div>Page <span class="pageNumber"></span></div>')

Storage Options (BYOS)

TakeOptions.url('...')
  .storageEnabled()
  .storagePath('{year}/{month}/{hash}.{ext}')
  .storageAcl('public-read')

Cache Management

// Get cached screenshot
const image = await client.cache.get('cache_xyz789');

// Delete single entry
await client.cache.delete('cache_xyz789');

// Bulk purge by keys
await client.cache.purge(['cache_abc', 'cache_def']);

// Purge by URL pattern
await client.cache.purgeUrl('https://mysite.com/blog/*');

// Purge by date
await client.cache.purgeBefore(new Date('2024-01-01'));

Webhook Helpers

import { verifyWebhook, parseWebhook } from 'renderscreenshot';

// Verify signature
const isValid = verifyWebhook(payload, signature, timestamp, secret);

// Parse event
const event = parseWebhook(payload);
if (event.type === 'screenshot.completed') {
  console.log(event.data.response?.url);
} else if (event.type === 'screenshot.failed') {
  console.log(event.data.error?.code, event.data.error?.message);
}

Error Handling

import { RenderScreenshotError } from 'renderscreenshot';

try {
  await client.take(TakeOptions.url('...'));
} catch (error) {
  if (error instanceof RenderScreenshotError) {
    console.log(error.httpStatus);  // 400, 429, etc.
    console.log(error.code);        // 'invalid_url', 'rate_limited'
    console.log(error.message);     // Human-readable message
    console.log(error.retryable);   // true/false
    console.log(error.retryAfter);  // Seconds (for rate limits)
  }
}

Error Codes

Code HTTP Retryable Description
invalid_request 400 No Malformed request
invalid_url 400 No Invalid URL provided
unauthorized 401 No Invalid API key
forbidden 403 No Access denied
not_found 404 No Resource not found
rate_limited 429 Yes Rate limit exceeded
timeout 408 Yes Screenshot timed out
render_failed 500 Yes Browser rendering failed
internal_error 500 Yes Internal server error

TypeScript

The SDK is written in TypeScript and provides full type definitions.

import {
  Client,
  TakeOptions,
  RenderScreenshotError,
  type ScreenshotResponse,
  type BatchResponse,
  type TakeOptionsConfig,
} from 'renderscreenshot';

Was this page helpful?