Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitchesSome links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
A callback (usually an HTTP webhook) lets your application submit a screenshot job, return immediately, and receive a POST when rendering succeeds or fails. The reliable pattern is: create a durable job record, submit an asynchronous request with webhook_url, authenticate and deduplicate every callback, persist the result or error, acknowledge quickly, and run slow processing separately. Keep polling as a reconciliation fallback.
What a callback changes in a screenshot workflow
A synchronous screenshot request keeps your connection open until the browser has loaded the page and produced an image. That is simple, but slow pages, JavaScript-heavy sites and queues can make request timeouts likely. An asynchronous request separates submission from rendering:
- Your service creates an internal job ID and stores the URL, capture options and expected callback.
- You submit the screenshot request with
async=true(ScreenshotOne) or the provider’s asynchronous POST flow (Urlbox), pluswebhook_url. - The provider acknowledges submission quickly and renders in its background queue.
- The provider POSTs a success or error event to your callback endpoint.
- Your endpoint verifies authenticity, records the event idempotently and returns a fast 2xx response.
- A worker downloads or processes the image, updates application state and notifies the original caller.
ScreenshotOne describes this pattern for asynchronous rendering, uploading to S3 and returning the file location to the webhook. Urlbox posts after a render succeeds or an error occurs.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteDesign the job record before writing the webhook
Do not make the callback your source of truth. Store a record before submitting the request so an event can be matched even if it arrives quickly.
#1 Best Overall
| Field | Purpose |
|---|---|
job_id |
Your stable identifier, generated before submission. |
requested_url and options |
Reconstructs what was requested and supports audits. |
provider and provider render ID |
Routes parsing and reconciliation. Urlbox calls its identifier renderId. |
| status | queued, succeeded, failed or duplicate. |
| result location | Durable object-storage key or provider URL, not merely a temporary link. |
| last event fingerprint | Prevents a retried or replayed callback from repeating side effects. |
| timestamps and raw event | Supports support requests, latency analysis and recovery. |
Pass an external identifier when the provider supports one. ScreenshotOne echoes external_identifier in the x-screenshotone-external-identifier header. Urlbox events include an event, a renderId and, on success, result.renderUrl plus render metadata.
Submit an asynchronous request
ScreenshotOne
Set async=true and provide webhook_url. If you ask ScreenshotOne to store the image in S3, add storage_return_location=true so the callback includes the storage location. Errors are not included by default; request them with webhook_errors=true. ScreenshotOne also exposes error information in headers.
const payload = {
url: "https://example.com",
async: true,
webhook_url: "https://app.example.com/webhooks/screenshotone",
external_identifier: "job_01J...",
webhook_errors: true,
storage_return_location: true
};
// Send payload using the provider's documented API endpoint and your API key.
// Save the returned provider reference with your internal job before responding.
The webhook body can contain screenshot_url and storage information. Use the storage location when available; a render URL may have a limited lifetime.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Urlbox
Urlbox accepts webhook_url and supports synchronous or asynchronous POST requests. Its asynchronous flow can be handled by webhook or polling. The JSON API is suited to larger HTML payloads and application-controlled workflows. Store the returned render reference, then accept events such as render.succeeded and failure events.
Rank #2
- Used Book in Good Condition
const request = {
url: "https://example.com",
webhook_url: "https://app.example.com/webhooks/urlbox",
// Include the provider's asynchronous option and your render settings.
metadata: { job_id: "job_01J..." }
};
Use the exact option names and authentication method shown in your Urlbox account documentation; the important workflow property is that submission and completion are separate requests.
Build a safe callback endpoint
Preserve the raw body and verify signatures
Parse JSON only after preserving the raw bytes. ScreenshotOne signs callbacks with HMAC-SHA-256 in X-ScreenshotOne-Signature, using a secret different from the API key. Compute the digest over the exact raw body and compare it in constant time. Never log the signing secret.
import express from "express";
import crypto from "node:crypto";
const app = express();
app.use(express.raw({ type: "application/json" }));
const secret = process.env.SCREENSHOTONE_WEBHOOK_SECRET;
function validSignature(raw, supplied) {
if (!supplied || !secret) return false;
const expected = crypto.createHmac("sha256", secret).update(raw).digest("hex");
const a = Buffer.from(expected, "utf8");
const b = Buffer.from(supplied, "utf8");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
app.post("/webhooks/screenshotone", async (req, res) => {
const raw = req.body; // preserve before JSON.parse
if (!validSignature(raw, req.get("X-ScreenshotOne-Signature"))) {
return res.sendStatus(401);
}
let event;
try { event = JSON.parse(raw.toString("utf8")); }
catch { return res.sendStatus(400); }
// Extract your external identifier or provider reference.
// Atomically insert an event key; if it already exists, do no work.
// Persist success (screenshot_url/storage) or failure (code/message).
// Enqueue image processing, then acknowledge immediately.
res.sendStatus(204);
});
app.listen(process.env.PORT || 3000);
For Urlbox, authenticate according to the mechanism enabled for your account. If no provider signature is available for a particular integration, put the callback behind HTTPS, use an unguessable path or token, restrict accepted methods and source traffic where practical, and treat every event as untrusted input.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Make processing idempotent
Callbacks can be duplicated, delayed or replayed. Use a database uniqueness constraint on a provider event ID when supplied; otherwise derive a fingerprint from the provider, render ID, event type and raw body hash. Process a success transition only when the job is still pending. A duplicate should receive a successful HTTP response after the first event has been recorded, not trigger another download, charge or publication.
Rank #3
Acknowledge before slow work
Return a 2xx response after authentication and durable enqueueing. Image transformations, S3 copies, thumbnail generation and notifications belong in a worker. If your process crashes after acknowledging but before enqueueing, a transactional outbox (event row plus queue record in one transaction) prevents silent loss.
Success, failure and storage handling
Success events
Validate that the event belongs to the requested job, then store the screenshot URL or cloud-storage location and the provider reference. Download into storage you control when the URL is temporary. Keep the original provider metadata for diagnosis.
Error events
Record the provider error code and message, mark the attempt failed and apply a bounded retry policy appropriate to the cause. Retry transient queue or network failures; do not blindly retry authentication errors, invalid URLs or pages that consistently fail. Alert only after your policy is exhausted.
Unknown and late events
Return a non-success response for an unverifiable callback. For an authenticated event with an unknown job, retain it in a quarantine table and investigate rather than creating a new job from attacker-controlled data. A late success after your own timeout should still be reconciled if the request is valid.
Rank #4
Polling versus callbacks
| Situation | Prefer | Reason |
|---|---|---|
| Many jobs or long renders | Callback | Workers are not tied up waiting and the provider pushes completion. |
| Local development or a one-off script | Polling | Less infrastructure than exposing a public HTTPS endpoint. |
| Provider retry behavior is undocumented | Callback plus reconciliation polling | You get low latency while periodic checks recover missed events. |
| Strict firewall or private network | Polling, or a public relay | The provider must be able to reach the callback URL. |
Do not promise yourself that a webhook will always arrive. The cited provider documentation does not establish a universal retry schedule. Run a reconciler that finds jobs stuck in queued beyond your service-level threshold and polls provider status where supported. Use exponential backoff with jitter and a maximum age.
Operational checklist
- Use HTTPS and authenticate every callback.
- Preserve the raw request body for signature verification and audit.
- Generate and store your job ID before submission.
- Persist provider IDs, event type, timestamps and the complete error details.
- Enforce idempotency with a unique event key or fingerprint.
- Limit body size, validate schemas and reject unexpected content types.
- Return 2xx quickly after durable enqueueing.
- Keep result files in durable storage and record their retention policy.
- Measure queue age, callback latency, signature failures, duplicate rate and reconciliation count.
- Provide an operator replay tool that re-runs processing from the stored event without accepting a new external request.
Common failures and fixes
The provider reports a webhook URL error
Check that DNS resolves publicly, the certificate is valid, the route accepts POST, and redirects are not required. Confirm your firewall, authentication middleware and request-size limit allow the provider’s request.
Every callback returns 401
For ScreenshotOne, verify you are using the webhook secret rather than the API key, the exact X-ScreenshotOne-Signature header, and the untouched raw body. Middleware that parses and reserializes JSON before verification changes the signed bytes.
The callback succeeds but no image is published
Inspect the event transaction and queue. A 2xx response must occur after the event and work item are durable, not before. Check that a worker is running and that the result URL has not expired.
Best Value
Jobs remain queued forever
Run reconciliation polling, inspect provider status and compare your stored provider ID with the submitted request. Distinguish a lost callback from a provider-side render failure.
Duplicate images or notifications appear
Add an atomic uniqueness constraint and make downstream actions conditional on a state transition from pending to succeeded. Never use “callback received” alone as permission to repeat side effects.
Or skip the browser setup
If you only need a dependable screenshot request rather than a custom browser-and-webhook stack, ScreenshotNeo provides a website screenshot API and MCP server. Its asynchronous jobs support signed webhooks, while one-call captures can return PNG, JPEG, WebP or PDF.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo documentation for callback and capture options. Before capture it accepts the cookie or consent banner like a visitor and removes more than 60 known consent platforms, newsletter popups and chat widgets; each cleanup step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing, and each response reports the page verdict and billing status in X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info and capture_pdf for Claude, Cursor and other MCP clients.
ScreenshotNeo includes full-page and selector capture, device presets and arbitrary viewports, retina scale, PDF controls, custom CSS and JavaScript, clicks, waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, chosen-TTL caching, signed image links, bulk capture of up to 100 URLs per call, usage and OpenAPI APIs, and parameter names compatible with those used by other screenshot APIs. Plans include 1,000 free shots each month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
Reference implementation flow
- Accept: validate the caller’s URL and options, create
job_id, and return HTTP 202 with that ID. - Submit: send the provider request with the callback URL and external identifier; save the provider reference.
- Receive: verify the signature, parse the event and locate the job.
- Commit: atomically record the event and transition the job once.
- Process: enqueue storage, transformation and notification work.
- Reconcile: poll stale jobs and quarantine unknown events.
- Report: expose job status and a durable result location to your caller.
Frequently Asked Questions
Can a webhook endpoint be private?
Only if the provider can reach it through your network arrangement. Otherwise expose a narrowly scoped public HTTPS relay that authenticates and forwards the event to your private queue.
Should I retry a callback request myself?
Retry your own downstream processing, not an already accepted event. Make event recording idempotent, and use reconciliation polling because provider retry guarantees are not established here.
What should I return for a duplicate event?
After authenticating it, return a successful response without repeating side effects. Your uniqueness constraint should make that path safe.
Quick Recap
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.

