Screenshot API Webhook Integration Guide
Configure HTTPS webhook endpoints, understand signed JSON payloads, implement an Express receiver, and learn retry semantics for async screenshot workflows.
Why webhooks?
Polling /screenshot/info from mobile clients or bursty frontends wastes bandwidth. Webhooks invert the flow: ScreenshotCenter POSTs to your URL when processing completes. Ideal for serverless workers, queue consumers, and notifying internal tools when a batch row finishes.
Product overview: Webhooks app. Step-by-step help: Webhook help article.
Configure the app
- Open the dashboard → Apps → Connect a new app → Webhook.
- Set your public HTTPS URL (must return
2xxwithin the timeout). - Optional: add a signing secret. When present, ScreenshotCenter sends
X-Signature: sha256=<hmac>over the raw body (see help for the exact header name in your workspace).
Trigger deliveries
Reference your webhook’s app_id via the apps query parameter on /screenshot/create (repeatable) or map custom path templates per app ID. The same mechanism fires after batch jobs complete so you can fan out notifications per row.
Sample payload
Your handler should tolerate additive fields. A typical completion payload includes identifiers, target URL, status, and a CDN link:
{
"event": "screenshot.completed",
"screenshot_id": "abc123",
"url": "https://example.com",
"status": "done",
"image_url": "https://cdn.screenshotcenter.com/abc123.png",
"created_at": "2026-03-24T12:00:00Z"
}
Express receiver (Node.js, ESM)
import express from 'express';
import crypto from 'crypto';
const app = express();
const secret = process.env.WEBHOOK_SECRET ?? '';
app.post(
'/webhooks/screenshotcenter',
express.json({
verify: (req, _res, buf) => {
req.rawBody = buf;
},
}),
(req, res) => {
const sig = req.headers['x-signature'];
if (secret && typeof sig === 'string' && req.rawBody) {
const expected =
'sha256=' +
crypto.createHmac('sha256', secret).update(req.rawBody).digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(sig);
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
return res.status(401).send('invalid signature');
}
}
const { event, screenshot_id, image_url } = req.body;
console.log('webhook', event, screenshot_id, image_url);
res.sendStatus(200);
},
);
app.listen(Number(process.env.PORT) || 3000, () => {
console.log('listening');
});
Deploy behind TLS termination (NGINX, Cloudflare, API Gateway). For serverless, configure the platform to pass the raw body bytes into your verifier.
Retries and idempotency
Failed deliveries retry with exponential backoff (up to several attempts). Make your handler idempotent: store processed screenshot_id values or event IDs in your database before returning 200 so duplicate posts do not enqueue work twice.
Use cases
- Trigger internal workflows when long PDF renders finish without holding a browser open in your API process.
- Notify operations when a batch screenshot row fails so you can fix data and replay.
- Forward events to Zapier/Make by chaining webhook → middleware → downstream HTTP.