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

Use a webhook when rendering a screenshot may take longer than your request should remain open. Your application submits an asynchronous capture with a callback URL, stores the returned job identifier, and then receives a server-to-server POST when the image or PDF is ready. The receiver must be publicly reachable, verify authenticity, acknowledge quickly, and hand slow processing to a queue. Retry schedules, payloads, retention, and recovery are provider-specific, so treat the provider’s current documentation as the contract.

The asynchronous screenshot lifecycle

A synchronous endpoint keeps the original HTTP request open until a browser loads the page and produces an image. Async mode separates submission from rendering:

  1. Submit. Send the target URL, capture options, async flag, and callback URL.
  2. Accept. The API returns an immediate acknowledgement (often a job ID; some services use 202 Accepted).
  3. Render. The provider runs its browser, waits according to your options, and stores or prepares the result.
  4. Deliver. It sends a POST to your callback URL containing status and result information.
  5. Process. Your service verifies the request, records it durably, acknowledges it, and lets a worker download, transform, or publish the asset.

ScreenshotOne documents asynchronous execution with a webhook URL and delivery of request results. ScreenshotMAX documents a 202 Accepted response followed by a callback. Neither description establishes a universal payload shape, so map fields from the API you selected rather than assuming names such as id, status, or image_url.

Design the submission request

Persist your own correlation ID together with the provider’s request or job ID before returning success to your caller. Include the URL, output format, viewport or device, full-page setting, and callback URL in the provider’s documented parameter names. Set a timeout on the submission request, but do not use that timeout to infer that rendering failed: the asynchronous job may still be running.

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

Minimal provider-neutral pseudocode

POST /capture
{
  "url": "https://example.com/report",
  "async": true,
  "webhook_url": "https://your.example/hooks/screenshots",
  "format": "png"
}

HTTP/1.1 202 Accepted
{
  "request_id": "provider-request-id"
}

Use the exact async and callback parameter names from the vendor. Store the response body, HTTP status, and your correlation ID in an encrypted or access-controlled database. Never put an API key in the callback URL itself; URLs are commonly logged by proxies and application servers.

Build a callback endpoint that is safe to operate

Reachability and HTTP behavior

  • Expose an HTTPS endpoint that the provider can reach from the public internet (or use the provider’s documented private-network option).
  • Accept POST with the documented content type and body size.
  • Handle provider health checks or a verification handshake if the service requires one.
  • Return a success status only after the event has been validated and durably recorded.

ScreenshotMAX states that its callback URL must be publicly accessible, accept POST, and return a 2xx response. GitHub’s webhook guidance gives a useful operational target: “Your server should respond with a 2XX response within 10 seconds of receiving a webhook delivery.” Confirm the selected screenshot API’s own timeout and acknowledgement rules.

Fast acknowledgement, slow work elsewhere

Do not download a large image, run OCR, notify users, and update several external systems inline. Verify the request, insert an event row, enqueue a job, and return 2xx. A worker can then fetch the result and perform expensive work. If the database or queue is unavailable, return a non-2xx response so the provider’s documented retry mechanism can operate; do not claim success and silently discard the event.

Idempotency and duplicate deliveries

Assume a callback can be delivered more than once. Save a stable provider event or job identifier (or a deterministic hash of the provider’s documented identifiers) under a unique constraint. A duplicate should produce a quick 2xx response without repeating publication, billing, or notifications. Because providers differ in how they identify events, ask which identifier is stable and whether it remains unique across retries.

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

Example receiver (Node.js and Express)

import express from "express";
import crypto from "node:crypto";

const app = express();
// Capture raw bytes; JSON parsing must happen after signature verification.
app.post("/hooks/screenshots",
  express.raw({ type: "application/json", limit: "2mb" }),
  async (req, res) => {
    const raw = req.body;
    const signature = req.get("X-ScreenshotOne-Signature");
    const secret = process.env.WEBHOOK_SIGNING_SECRET;

    if (!signature || !secret) return res.sendStatus(401);
    const expected = crypto.createHmac("sha256", secret)
      .update(raw).digest("hex");
    const a = Buffer.from(signature, "utf8");
    const b = Buffer.from(expected, "utf8");
    if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
      return res.sendStatus(401);
    }

    let event;
    try { event = JSON.parse(raw.toString("utf8")); }
    catch { return res.sendStatus(400); }

    // Insert event with a unique provider-event/job ID, then enqueue work.
    await saveEventAndEnqueue(event);
    return res.sendStatus(204);
  });

app.listen(3000);

The header and algorithm in this example follow ScreenshotOne’s documented convention. ScreenshotOne says its webhook secret is different from the API key. ScreenshotMAX documents optional HMAC-SHA256 signing using its secret_key. Do not copy either convention to another provider without checking its current documentation.

Verify signatures correctly

A callback URL by itself does not prove who sent a request. When signing is available, verify before triggering any meaningful action:

  • Read the exact raw request bytes. Do not parse and reserialize JSON first; whitespace and key order can change the digest.
  • Use the provider’s webhook secret, not the API key, when the provider distinguishes them.
  • Use the exact header encoding and algorithm (for example, HMAC SHA-256) documented by that provider.
  • Compare signatures in constant time and reject missing, malformed, or mismatched values.
  • Keep secrets in a secret manager or environment configuration, rotate them according to the provider’s process, and never log them.

Some services expose a switch to disable signing. Treat that as a security trade-off, not a performance optimization; leave verification enabled unless you have a documented alternative such as mutually authenticated TLS and a restricted network path.

What belongs in the callback payload?

Providers commonly send a completion state plus a request identifier and a result location, but the exact fields differ. The result may be an image URL, a storage key, a PDF location, or an error object. Build a strict parser for required fields and retain the original body for diagnosis. Reject an unknown status only if the provider’s contract says unknown values are invalid; otherwise record it and route it for review. Never trust a callback’s URL or filename as a safe local path without validation.

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

Failure handling and recovery

When your endpoint is down

Find out, for the chosen API, which HTTP codes count as acknowledgement, whether connection timeouts and non-2xx replies trigger retries, the number and spacing of attempts, and whether failed deliveries appear in a dashboard. ScreenshotRun publishes one vendor-specific example of an initial delivery followed by three retries at increasing delays, then fallback retrieval by screenshot ID. That schedule is not an industry standard.

When delivery is lost

Provide a recovery path that does not depend solely on the callback: a status or retrieval endpoint, a provider dashboard, or a durable result location. Record the provider request ID at submission so an operator can reconcile jobs. Ask how long results remain available and whether callback result URLs expire. ScreenshotOne documents S3-oriented storage and notes that webhook caching is not supported; ScreenshotMAX documents callback delivery and an async-job dashboard. These differences affect your recovery design.

When rendering fails

Distinguish a successful callback carrying a failed render from a callback that never arrived. Preserve provider error codes and messages, classify transient network or timeout errors separately from permanent target-page failures, and retry only according to the provider’s limits. If you retry submission, create a new correlation ID and link it to the original to avoid duplicate publishing.

Provider comparison checklist

Question Why it matters What to document
Async acknowledgement Determines when your request can close and how jobs are tracked. HTTP status, request ID, and status endpoint.
Callback requirements Prevents unreachable or rejected deliveries. HTTPS/public access, method, content type, timeout, and accepted 2xx codes.
Authenticity Stops forged captures and unauthorized downstream actions. Default/optional signing, header, secret, algorithm, and raw-body rules.
Result handling Determines storage, permissions, and download timing. URL or object key, expiry, format, and required cloud storage.
Failure recovery Defines your behavior during outages. Retry schedule, dashboard visibility, retention, polling, and replay tools.

ScreenshotOne and ScreenshotMAX document different pieces of this model; their materials do not establish a complete comparison of pricing, uptime, or every recovery policy. Verify each item in the current provider documentation before committing to an integration.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
API Design Patterns
  • API Design Patterns
  • ABIS BOOK
  • Manning Publications
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

ScreenshotNeo provides asynchronous jobs with signed webhooks, so you can request a capture without operating a browser worker. It removes cookie/consent banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server gives Claude, Cursor, and other MCP clients take_screenshot, get_page_info, and capture_pdf tools. The free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 shots.

Use the documented options and webhook settings at ScreenshotNeo’s API documentation. A one-call capture looks like this:

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

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)

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}`);

Create a free ScreenshotNeo account to get 1,000 screenshots a month with no card.

Troubleshooting checklist

401 or 403 from the callback

Check that you are using the webhook secret, not the API key; verify the exact header, encoding, and raw body; and confirm the secret belongs to the same environment as the job.

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

Provider reports timeout

Move downloads and downstream calls to a queue, return 2xx after durable recording, and confirm your reverse proxy is not imposing a shorter timeout.

No callback arrives

Confirm DNS, TLS, firewall rules, public reachability, HTTP method, and path. Inspect the provider’s delivery logs and use the stored request ID with its status or retrieval API.

Duplicate images are published

Add a unique constraint on the provider event/job ID and make the worker idempotent. A repeated callback should be acknowledged without repeating side effects.

Valid JSON fails verification

Ensure middleware has not parsed, reformatted, decompressed, or transcoded the body before HMAC calculation. Verify against the exact bytes received.

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

Operational, performance, and cost notes

  • Use a queue with bounded concurrency so a traffic spike does not exhaust database connections or outbound bandwidth.
  • Set provider wait conditions deliberately: network-idle waits improve completeness but increase latency and may encounter never-ending analytics requests.
  • Choose output format and dimensions for the consumer. WebP or JPEG can reduce transfer size; PNG is preferable for lossless text and UI details.
  • Track submission, render, callback, download, and publication timestamps separately. This reveals whether latency comes from the provider or your own queue.
  • Cache only when the target content and privacy policy permit it. Confirm whether the provider bills cache hits and whether webhook delivery is cacheable; ScreenshotOne says webhook caching is not supported.
  • Budget for successful captures according to the provider’s billing definition, and monitor failed, cached, or blocked outcomes separately when the API exposes those classifications.

FAQ

Is a webhook the same as polling?

No. A webhook pushes completion to your endpoint; polling repeatedly asks a status endpoint. Keep polling as a recovery path when the provider supports it.

Should I expose my internal job ID?

Use an opaque correlation value. Store the mapping to provider identifiers internally and avoid putting secrets or sensitive business data in callback URLs or response bodies.

Can I acknowledge before verifying a signature?

Not safely. Verify and durably record the event first; otherwise an attacker could cause untrusted work while your endpoint reports success.

How long should I retain callback bodies?

Retain enough original data to audit and replay according to your privacy and compliance requirements, while following the provider’s result-retention and data-processing terms.

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

Quick Recap

SaleBestseller No. 1
Bestseller No. 3
Bestseller No. 4
API Design Patterns
API Design Patterns
API Design Patterns; ABIS BOOK; Manning Publications
$59.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.