Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use a small HTTP API to validate and enqueue capture requests, then let separate workers render pages in headless Chrome and save the images. This keeps browser work out of the request path and gives you a place to manage job status, retries, and bursts.

How the service fits together

Puppeteer is a JavaScript browser-automation API that runs headless by default and can capture a page or a selected element. BullMQ is a Node.js queue built on Redis: the API adds jobs, and connected workers pick them up. Combining them gives you an asynchronous service, though the complete design below is an architectural example—not a prescribed end-to-end recipe from either project.

  1. API: authenticate callers, validate the URL and options, enqueue a compact job, and return a job ID.
  2. Queue: hold pending work in Redis so capture jobs can wait for available workers.
  3. Worker: open the page with Puppeteer, wait for an appropriate readiness condition, take the screenshot, and save it.
  4. Result delivery: expose job status and a protected way to retrieve completed output.

For a prototype, one process can serve the API and run a worker. Separate API and worker processes when you need to scale them independently or isolate browser execution. In either shape, Redis and the browser still require operational monitoring.

Choose what the API accepts

Keep the first contract small

A useful initial request can accept a URL and a few explicit options: viewport width and height, image format, full-page capture, and an optional CSS selector for an element. Puppeteer supports viewport configuration and screenshots; Chrome DevTools Protocol also describes PNG, JPEG, and WebP capture formats and clipping parameters. Set your own maximum dimensions, payload size, navigation time, and accepted formats before enqueueing. These bounds are service policy, not defaults established by the browser libraries.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Sale
Logitech Brio 101 Full HD 1080p Webcam for Streaming and Meetings - Black
  • Compatible with Nintendo Switch 2’s new GameChat mode
  • Auto-Light Balance: RightLight boosts brightness by up to 50%, reducing shadows so you look your best—compared to previous-generation Logitech webcams (1)
  • Privacy with a Slide: The integrated webcam cover makes it easy to get total, reliable privacy when you're not on a video call
  • Built-In Mic: The built-in microphone lets others hear you clearly during video calls
  • Easy Plug-And-Play: The Brio 101 works with most video calling platforms, including Microsoft Teams, Zoom and Google Meet—no hassle; it just works

For element capture, require the selector to match before taking the screenshot. Puppeteer’s element screenshot method attempts to scroll a hidden element into view by default. Treat a missing selector as a job failure with a useful status rather than silently returning a full-page image.

Validate before queueing

Reject malformed URLs and unsupported schemes at the API boundary, and validate all option types and ranges. Syntax validation is not a security boundary: checking that a URL starts with http: or https: does not make arbitrary navigation safe. The browser worker needs a separately reviewed network-access policy before the service is exposed to untrusted callers.

Build a minimal asynchronous service

Prerequisites and setup

This example uses Node.js, Express, BullMQ, Puppeteer, and a reachable Redis server. Install the current compatible package versions for your runtime; no version pin is implied here.

Rank #2
Sale
Logitech C270 720p Webcam Plug-and-Play Wide Screen Video Calling - Black
  • Compatible with Nintendo Switch 2’s new GameChat mode
  • Crisp HD 720p/30 fps video calls with diagonal 55° field of view and auto light correction. Compatible with popular platforms including Skype and Zoom.
  • The built-in noise-reducing mic makes sure your voice comes across clearly up to 1.5 meters away, even if you’re in busy surroundings.
  • C270’s RightLight 2 feature adjusts to lighting conditions, producing brighter, contrasted images to help you look good in all your conference calls.
  • The adjustable universal clip lets you attach the camera securely to your screen or laptop, or fold the clip and set the webcam on a shelf. You’re always ready for your next video call.
npm init -y
npm install express bullmq puppeteer

Start Redis using the method appropriate for your environment. The code below assumes it is reachable at 127.0.0.1:6379. Save the following as server.js and worker.js in the same directory. The example writes files to a local screenshots directory; use durable object storage and access-controlled delivery for a deployed service.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

HTTP API: validate, enqueue, check status, fetch result

const express = require('express');
const { Queue } = require('bullmq');
const path = require('node:path');
const fs = require('node:fs');

const app = express();
app.use(express.json({ limit: '32kb' }));
const connection = { host: '127.0.0.1', port: 6379 };
const queue = new Queue('screenshots', { connection });
const outputDir = path.join(__dirname, 'screenshots');
fs.mkdirSync(outputDir, { recursive: true });

app.post('/jobs', async (req, res, next) => {
  try {
    const { url, width = 1365, height = 768, format = 'png', fullPage = false, selector } = req.body ?? {};
    let parsed;
    try { parsed = new URL(url); } catch { return res.status(400).json({ error: 'A valid URL is required.' }); }
    if (!['http:', 'https:'].includes(parsed.protocol)) {
      return res.status(400).json({ error: 'Only HTTP and HTTPS URLs are accepted.' });
    }
    if (!Number.isInteger(width) || width < 320 || width > 2560 ||
        !Number.isInteger(height) || height < 200 || height > 2560) {
      return res.status(400).json({ error: 'Viewport dimensions are outside this service's allowed range.' });
    }
    if (!['png', 'jpeg', 'webp'].includes(format) || typeof fullPage !== 'boolean' ||
        (selector !== undefined && (typeof selector !== 'string' || selector.length > 500))) {
      return res.status(400).json({ error: 'Invalid capture options.' });
    }

    const job = await queue.add('capture', { url: parsed.href, width, height, format, fullPage, selector }, {
      attempts: 2,
      backoff: { type: 'exponential', delay: 1000 },
      removeOnComplete: { age: 86400 },
      removeOnFail: { age: 604800 }
    });
    res.status(202).json({ id: job.id, statusUrl: `/jobs/${job.id}` });
  } catch (error) { next(error); }
});

app.get('/jobs/:id', async (req, res, next) => {
  try {
    const job = await queue.getJob(req.params.id);
    if (!job) return res.status(404).json({ error: 'Job not found or its queue record expired.' });
    const state = await job.getState();
    const response = { id: job.id, state };
    if (state === 'completed') response.resultUrl = `/jobs/${job.id}/result`;
    if (state === 'failed') response.error = job.failedReason;
    res.json(response);
  } catch (error) { next(error); }
});

app.get('/jobs/:id/result', async (req, res, next) => {
  try {
    if (!/^[A-Za-z0-9_-]+$/.test(req.params.id)) return res.sendStatus(400);
    const job = await queue.getJob(req.params.id);
    if (!job || await job.getState() !== 'completed') return res.status(404).json({ error: 'Result is not available.' });
    const file = job.returnvalue.file;
    if (typeof file !== 'string' || path.basename(file) !== file) return res.sendStatus(404);
    res.sendFile(path.join(outputDir, file));
  } catch (error) { next(error); }
});

app.listen(3000, () => console.log('Screenshot API listening on port 3000'));

The dimension limits and retry count above are example service choices, not universal safe or optimal settings. The result endpoint is intentionally unauthenticated to keep the sample short; do not expose private captures this way. Authenticate API calls and authorize result access in a real deployment. Queue records are retained for one day after completion and one week after failure in this example, while the image files have no cleanup policy—add storage retention and deletion deliberately.

Worker: render and save the capture

const { Worker } = require('bullmq');
const puppeteer = require('puppeteer');
const path = require('node:path');
const fs = require('node:fs/promises');

const connection = { host: '127.0.0.1', port: 6379 };
const outputDir = path.join(__dirname, 'screenshots');
let browser;

async function start() {
  await fs.mkdir(outputDir, { recursive: true });
  browser = await puppeteer.launch();
  const worker = new Worker('screenshots', async job => {
    const { url, width, height, format, fullPage, selector } = job.data;
    const page = await browser.newPage();
    try {
      await page.setViewport({ width, height });
      await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 });
      if (selector) {
        const element = await page.waitForSelector(selector, { timeout: 10000 });
        if (!element) throw new Error('Requested selector was not found.');
        const file = `${job.id}.${format}`;
        await element.screenshot({ path: path.join(outputDir, file), type: format });
        return { file };
      }
      const file = `${job.id}.${format}`;
      const options = { path: path.join(outputDir, file), type: format, fullPage };
      if (format !== 'png') options.quality = 80;
      await page.screenshot(options);
      return { file };
    } finally {
      await page.close();
    }
  }, { connection, concurrency: 2 });

  worker.on('failed', (job, error) => {
    console.error('Capture failed', job?.id, error.message);
  });
  worker.on('error', error => console.error('Worker error', error));
  const shutdown = async () => {
    await worker.close();
    if (browser) await browser.close();
    process.exit(0);
  };
  process.once('SIGINT', shutdown);
  process.once('SIGTERM', shutdown);
}

start().catch(error => {
  console.error(error);
  process.exit(1);
});

The worker reuses one browser process and opens a page per job; that lifecycle is a starting point, not a guarantee that a browser can run indefinitely without recovery. The sample uses a two-job concurrency setting and an 80 quality value for JPEG/WebP. Tune both against representative pages and the memory and CPU available to each worker. If a browser process crashes, add supervised restart behavior rather than assuming a queue retry alone will restore it.

Rank #3
Sale
NexiGo N60 1080P Webcam with Microphone, Software Control & Privacy Cover, USB HD Computer Web Camera, Plug and Play, for Zoom/Skype/Teams, Conferencing and Video Calling
  • 【Full HD 1080P Webcam】Powered by a 1080p FHD two-MP CMOS, the NexiGo N60 Webcam produces exceptionally sharp and clear videos at resolutions up to 1920 x 1080 with 30fps. The 3.6mm glass lens provides a crisp image at fixed distances and is optimized between 19.6 inches to 13 feet, making it ideal for almost any indoor use.
  • 【Wide Compatibility】Works with USB 2.0/3.0, no additional drivers required. Ready to use in approximately one minute or less on any compatible device. Compatible with Mac OS X 10.7 and higher / Windows 7, 8, 10 & 11 / Android 4.0 or higher / Linux 2.6.24 / Chrome OS 29.0.1547 / Ubuntu Version 10.04 or above. Not compatible with XBOX/PS4/PS5.
  • 【Built-in Noise-Cancelling Microphone】The built-in noise-canceling microphone reduces ambient noise to enhance the sound quality of your video. Great for Zoom / Facetime / Video Calling / OBS / Twitch / Facebook / YouTube / Conferencing / Gaming / Streaming / Recording / Online School.
  • 【USB Webcam with Privacy Protection Cover】The privacy cover blocks the lens when the webcam is not in use. It's perfect to help provide security and peace of mind to anyone, from individuals to large companies. 【Note:】Please contact our support for firmware update if you have noticed any audio delays.
  • 【Wide Compatibility】Works with USB 2.0/3.0, no additional drivers required. Ready to use in approximately one minute or less on any compatible device. Compatible with Mac OS X 10.7 and higher / Windows 7, 10 & 11, Pro / Android 4.0 or higher / Linux 2.6.24 / Chrome OS 29.0.1547 / Ubuntu Version 10.04 or above. Not compatible with XBOX/PS4/PS5.

Submit a job and poll it

curl -X POST http://localhost:3000/jobs 
  -H 'Content-Type: application/json' 
  -d '{"url":"https://example.com","width":1365,"height":768,"format":"png","fullPage":true}'

The API returns HTTP 202 with an ID and status path. Poll that path until the state is completed or failed; on completion, request the returned result URL. A client that cannot poll can instead use a completion callback, but then the service must authenticate callbacks and define delivery/retry behavior.

Choose readiness and capture behavior

Do not assume network idle means visually ready

Puppeteer’s screenshot guide demonstrates navigation with waitUntil: 'networkidle2', followed by Page.screenshot(). That is an example, not a universal readiness rule. Pages with persistent connections can fail to become network-idle, while pages that load content after navigation may appear incomplete at domcontentloaded. Offer a small set of explicit readiness strategies—such as a selector or a bounded delay—and document their trade-offs. Always impose a maximum navigation and wait duration.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Make output choices explicit

Viewport screenshots are cheaper to constrain and easier to predict in dimensions; full-page captures include content beyond the initial viewport but can produce very tall images. Element captures are useful for a component but depend on the selector matching the intended element. Choose defaults and maximums that suit your service, and return metadata that records the effective options. Chrome DevTools Protocol exposes lower-level screenshot parameters including format, quality, and clipping; use Puppeteer for the ordinary Node.js case, and consider the protocol directly only if you need its lower-level control.

Rank #4
Sale
EMEET C960 1080P Webcam with Microphone, 2 Mics, 90° FOV, Computer Camera
  • 1080P Webcam with Cover for Video Calls - EMEET computer webcam provides design and Optimization for professional video streaming. Realistic 1920 x 1080p video, 5-layer anti-glare lens, providing smooth video. C960 computer camera delivers 1920x1080 video with fixed focus (11.8–118.1 inches), so as to provide a clearer image. C960 USB webcam has a cover and can be removed automatically to meet your needs for privacy. For optimal image performance, use the webcam in a well-lit environment.
  • Built-in 2 Omnidirectional Mics - EMEET webcam with microphone for desktop features 2 built-in omnidirectional microphones, picking up your voice to create clear audio for communication. When installing the webcam, select EMEET C960 as the default microphone input device in your computer and video applications and select C960 as the default device in Zoom/Teams and ensure microphone permissions are enabled for proper use. Please note that C960 does not include built-in speakers.
  • Automatic Light Adjustment - Automatic exposure adjustment is applied in EMEET HD webcam 1080p so that the streaming webcam can deliver stable image performance. EMEET C960 camera for computer also features color adjustment and exposure optimization to help you look your best. For optimal video quality, it is recommended to use the webcam in normal or well-lit environments and select suitable video settings in your application. Proper lighting helps achieve a clearer and more balanced image.
  • Plug-and-Play & Upgraded USB Connectivity - New C960 webcam features both USB Type-A & A-to-C adapter connections for wider compatibility. For stable performance, connect the webcam directly to the computer's main USB port and ensure the device is recognized correctly. If a hub or docking station is used, please ensure it provides sufficient power and stable data transmission, as limited ports may affect performance. 90° wide-angle lens captures more participants without frequent adjustments.
  • High Compatibility & Multi Application - C960 webcam for laptop is compatible with Windows 10/11, macOS 10.14+, and Android TV 7.0+. Not supported: Windows Hello, TVs, tablets, or game consoles. It works with Zoom, Teams, Facetime, Google Meet, YouTube and more. Please select C960 webcam as the default camera and microphone device in your application and ensure camera/microphone permissions are enabled, especially on macOS. (Tips: Incompatible with Windows Hello)
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Make the queue safe under load and failure

Concurrency, rate limits, and retries

BullMQ supports worker concurrency, multiple workers, retries, and rate limiting. Start with conservative worker concurrency, then measure memory use, CPU, queue wait time, capture duration, and failure rates across representative sites before raising it. There is no general throughput or memory figure that can be safely inferred for all pages and deployment environments. Add queue-level rate controls where callers or target sites need bounded request rates.

Retry transient navigation and infrastructure failures selectively. Invalid input, prohibited destinations, and a selector that definitively does not exist are generally not made better by repeating the same job. BullMQ describes its goal as “Exactly once queue semantics,” while noting delivery can be at least once in the worst case. Therefore, design capture effects to tolerate repeat execution: use stable job identifiers where duplicate suppression is needed, write output deterministically, and avoid charging or notifying twice just because a job was retried.

Keep Redis payloads small and expose lifecycle state

Queue only the URL and compact capture options; do not put screenshot bytes into Redis. Save output in object storage or a managed file store and retain a reference and completion metadata in the job result. Define how long job records and images remain available, who can retrieve them, and how expired results are deleted. These are service design decisions rather than storage policies provided by Puppeteer or BullMQ.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Best Value
Logitech C920x HD Pro PC Webcam Full 1080p/30fps Video - Black
  • Compatible with Nintendo Switch 2’s new GameChat mode
  • HD lighting adjustment and autofocus: The Logitech webcam automatically fine-tunes the lighting, producing bright, razor-sharp images even in low-light settings. This makes it a great webcam for streaming and an ideal web camera for laptop use
  • Advanced capture software: Easily create and share video content with this Logitech camera that is suitable for use as a desktop computer camera or a monitor webcam
  • Stereo audio with dual mics: Capture natural sound during calls and recorded videos with this 1080p webcam, great as a video conference camera or a computer webcam
  • Full HD 1080p video calling and recording at 30 fps. You'll make a strong impression with this PC webcam that features crisp, clearly detailed, and vibrantly colored video

Protect the browser from arbitrary URLs

A public screenshot endpoint can be asked to navigate to caller-selected destinations. A queue does not solve that risk, and scheme validation alone is insufficient. Before accepting untrusted URLs, get a security review and define controls for private and internal IP ranges, DNS resolution and rebinding, redirects, non-HTTP schemes, local services, browser downloads, request size and time limits, and outbound network access. This list identifies areas to review; it is not a complete security specification or a claim that any particular implementation is safe.

  • Run browser workers isolated from sensitive networks and credentials.
  • Apply outbound network policy at an enforcement point that accounts for redirects and resolved addresses.
  • Set bounded time and resource limits, and decide explicitly whether downloads are disabled.
  • Test the exact controls against the deployment environment before exposing the endpoint.

Also authenticate callers, cap their request rate and concurrent jobs, and ensure result URLs cannot expose another user’s captures. Do not deploy the sample’s public result route unchanged for sensitive or multi-tenant workloads.

When to use a queue—and what it costs operationally

Design Request behavior Operational trade-off
Single process with synchronous capture The HTTP request stays open while the browser navigates and renders. Simpler starting point, but slow or bursty captures occupy request handling capacity.
API plus queue and workers The API returns a job ID; capture happens outside the request path. Adds Redis, queue operations, status/result handling, and worker operations; lets capture capacity scale separately and smooth bursts.

Neither shape has a universal winner. Compare request latency, burst smoothing, throughput, recovery behavior, result delivery, complexity, and worker isolation for your expected workload. For queue-based capture, budget for browser CPU and memory as well as Redis, output storage, retention, and monitoring. Benchmark real target pages in the intended environment instead of promising a throughput or cost figure from a generic example.

Troubleshoot common failures

  • Jobs remain waiting: confirm Redis is reachable, the queue name matches in API and worker, and a worker process is running.
  • Jobs fail on navigation timeout: the site may be slow, unreachable, or waiting on behavior not covered by the chosen readiness condition. Use a bounded, site-appropriate wait strategy; do not remove timeouts.
  • Blank or incomplete captures: check whether content loads after domcontentloaded. Wait for a page-specific selector or a deliberate bounded delay where appropriate.
  • Selector capture fails: verify the selector exists in the rendered page and account for content that appears asynchronously. The sample waits up to ten seconds.
  • Worker memory rises or jobs become unstable: reduce concurrency, investigate unusually large pages and full-page images, and monitor browser restarts and failure patterns before increasing capacity.
  • Repeated failed jobs: classify the failure. Keep bounded retries for transient errors; avoid retrying invalid requests or deterministic missing-element errors.
  • Result URL returns not found: check job state and retention; the example removes completed queue records after a day and does not provide image cleanup or durable storage.

Or skip the browser setup

ScreenshotNeo provides a website screenshot API and MCP server. Its GET endpoint returns a screenshot or PDF, and the capture can accept cookie/consent banners like a visitor before removing more than 60 known consent platforms, newsletter popups, and chat widgets; those steps can each be turned off. Bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses include X-Page-Verdict and X-Billed headers. Its MCP tools—take_screenshot, get_page_info, and capture_pdf—are for Claude, Cursor, and other MCP clients.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

One cURL request (see the ScreenshotNeo API documentation) saves a WebP capture:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Equivalent Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Or Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo includes 1,000 screenshots a month free with no card; paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month, no card required.

Quick Recap

SaleBestseller No. 1
Logitech Brio 101 Full HD 1080p Webcam for Streaming and Meetings - Black
Logitech Brio 101 Full HD 1080p Webcam for Streaming and Meetings - Black
Compatible with Nintendo Switch 2’s new GameChat mode; Built-In Mic: The built-in microphone lets others hear you clearly during video calls
$35.90
SaleBestseller No. 2
Logitech C270 720p Webcam Plug-and-Play Wide Screen Video Calling - Black
Logitech C270 720p Webcam Plug-and-Play Wide Screen Video Calling - Black
Compatible with Nintendo Switch 2’s new GameChat mode
$16.89
Bestseller No. 5
Logitech C920x HD Pro PC Webcam Full 1080p/30fps Video - Black
Logitech C920x HD Pro PC Webcam Full 1080p/30fps Video - Black
Compatible with Nintendo Switch 2’s new GameChat mode; Fully compatible with Windows 11
$69.99

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.