Language

Node.js Screenshot API

Server-side screenshot capture with Node.js — for backend services, Express/Fastify APIs, CLI tools, and automation scripts. This guide covers the Node.js screenshot API for server-side use only: streaming responses to disk or S3, Express screenshot middleware, cron jobs, and integrating with Bull/BullMQ for batch processing. Keep API keys on the server where they belong.

Quick summaryServer-side Node.js screenshot capture for batch jobs, queue workers, and API endpoints. Use native fetch (Node 18+) or undici. Concurrency-bound via p-limit; stream large bodies to storage.

Quick Start

1

Install dependencies

Run npm install node-fetch (for Node.js < 18) or use the built-in fetch API in Node.js 18+.

2

Get your API key

Sign up for Screenshotly and get your API key from the dashboard.

3

Copy the code example

Use our Node.js code example as a starting point.

4

Customize and integrate

Modify the code to fit your specific use case and requirements.

Code Example

// Node.js
const https = require('https');
const fs = require('fs');

const captureScreenshot = async (url, outputPath) => {
  const response = await fetch('https://api.screenshotly.app/screenshot', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.SCREENSHOTLY_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      url,
      device: 'desktop',
      format: 'png',
    }),
  });
  
  const buffer = await response.arrayBuffer();
  fs.writeFileSync(outputPath, Buffer.from(buffer));
};

When to Use Node.js with Screenshotly

Use the Node.js integration for server-side screenshot capture only. Ideal for Express/Fastify backend APIs that generate screenshots on demand, CLI tools, cron jobs, CI/CD pipelines, and batch processing. Choose Node.js when you need to process screenshots in bulk, stream to cloud storage, or run captures as background jobs — all without exposing your API key to the client.

Node.js Best Practices

Use a worker queue (Bull, BullMQ, or Bee-Queue) for server-side batch processing instead of Promise.all() to control concurrency and handle retries.

Stream the API response directly to disk or S3 with pipeline() from 'stream/promises' to avoid buffering large images in memory.

Set an AbortSignal timeout on every fetch call to prevent hung requests from blocking your Node.js event loop.

Store API keys in environment variables and load them with dotenv in development. In production, use AWS Secrets Manager or Vault — never expose keys to the browser.

Node.js: Production Notes

Node.js is the most common runtime for screenshot integration because most backend pipelines that generate screenshots already live in the same process as the app that triggered them. The core primitive is a single fetch() call with the image returned as a buffer. What elevates production code from dev code is everything around that call: connection reuse, concurrency control, retry semantics, and stream handling for large outputs.

For batch jobs, cap parallel captures with p-limit at 5–10. Without a limiter, a naive `Promise.all()` over 1,000 URLs will open 1,000 concurrent requests, breach rate limits, and likely crash with memory pressure.

Error Handling Recipes

Concrete strategies for each failure mode. Do not silently swallow errors — surface them to your monitoring so the pipeline is observable.

HTTP 401 / 403

Log the masked API key prefix; do not retry. Alert on-call if seen in production — usually indicates a rotated or misconfigured secret.

HTTP 429

Exponential backoff respecting the Retry-After header. For queue workers, requeue the job rather than blocking the worker thread.

if (res.status === 429) {
  const retryAfter = parseInt(res.headers.get('retry-after') || '1', 10);
  await new Promise(r => setTimeout(r, retryAfter * 1000));
  return capture(url, attempt + 1);
}

Response body too large for memory

Stream response.body directly to S3/GCS upload instead of buffering. Saves ~100 MB peak memory on the largest captures.

Production Hardening Checklist

The difference between dev code and prod code. Work through these before putting Node.js captures on a critical path.

  • Use native fetch (Node 18+) or undici directly. node-fetch is deprecated for new projects.
  • Bound concurrency with p-limit or similar (default 5–10).
  • Stream large response bodies to storage rather than buffering.
  • Retry 5xx with jittered exponential backoff; never retry 4xx other than 429.
  • Ack queue messages after persist, not after capture.
  • Handle SIGTERM gracefully — drain in-flight captures before exit.

Rate-Limit Strategy

Respect the rate-limit headers on every response (X-RateLimit-Remaining, X-RateLimit-Reset). For multi-worker deployments, coordinate via Redis — otherwise each worker will hammer the API independently.

When Node.js isn't the right fit

Node.js works well for most capture workloads, but these patterns are legitimate reasons to pick a different stack:

  • Your runtime is Deno or Bun and you need exact Node compatibility — the fetch API is similar but not identical; audit before porting production code.
  • You run exclusively in AWS Lambda with sub-512MB memory and need full-page captures of large SPAs — memory pressure can OOM-kill short-lived containers.
  • You need to drive a multi-step browser automation flow (form fills, OAuth) — that is Playwright territory, not screenshot API territory.

Want a step-by-step walkthrough?

Read the full Node.js tutorial →

API Reference

EndpointPOST /api/screenshot
AuthenticationBearer token
Content-Typeapplication/json
View full API docs

Frequently Asked Questions

How do I handle large volumes of screenshots in Node.js?

Use async/await with Promise.all() for parallel processing, but limit concurrency to avoid rate limits. Consider using a queue system like Bull or Agenda for high-volume processing with proper retry logic.

What's the best way to store API keys in Node.js?

Use environment variables with the dotenv package. Never hardcode API keys in your source code. For production, use secure secret management services like AWS Secrets Manager or Azure Key Vault.

Can I use Screenshotly with Express.js APIs?

Absolutely! Create API endpoints that accept URLs and return screenshots. You can stream the response directly to clients or save to cloud storage like AWS S3 for later retrieval.

How do I handle timeouts and retries in Node.js?

Set appropriate timeout values using AbortController or request timeout options. Implement exponential backoff for retries on temporary failures (429, 500, 502, 503 status codes).

Start building with Node.js

Get your API key and start capturing screenshots in minutes.

Other Languages