Webhooks

Webhooks deliver real-time HTTP POST notifications to your endpoint when events occur in Captureze.

Note: Webhooks are available on Starter and Pro plans.

Setting Up Webhooks

  1. Go to Settings → Webhooks
  2. Click Add Webhook
  3. Enter your endpoint URL (must be HTTPS)
  4. Select which events to receive
  5. Save — copy the secret shown once and store it securely

You can also manage webhooks via the API: POST /api/webhooks.

Events

screenshot.completed

A screenshot was successfully captured (on schedule or manually).

screenshot.failed

A screenshot capture failed (timeout, unreachable URL, etc.).

diff.detected

A visual change was detected above the configured diff_threshold for the schedule.

Request Headers

Each webhook request includes these headers:

Header Description
Content-Type application/json
X-Captureze-Signature HMAC-SHA256 hex signature of the request body
X-Captureze-Event Event name (e.g. screenshot.completed)
X-Captureze-Delivery Unique UUID for this delivery attempt

Payload Format

screenshot.completed

{
  "event": "screenshot.completed",
  "timestamp": "2025-01-15T10:30:00Z",
  "data": {
    "scheduleId": "550e8400-e29b-41d4-a716-446655440000",
    "scheduleName": "Example Monitor",
    "scheduleUrl": "https://example.com",
    "screenshotId": "7f3e9a12-...",
    "screenshotUrl": "https://captureze.com/screenshots/...",
    "fileSize": 284512,
    "diffPercent": 0.5,
    "storageType": "platform"
  }
}

screenshot.failed

{
  "event": "screenshot.failed",
  "timestamp": "2025-01-15T10:30:00Z",
  "data": {
    "scheduleId": "550e8400-...",
    "scheduleName": "Example Monitor",
    "url": "https://example.com",
    "error": "Navigation timeout exceeded"
  }
}

diff.detected

{
  "event": "diff.detected",
  "timestamp": "2025-01-15T10:30:00Z",
  "data": {
    "scheduleId": "550e8400-...",
    "scheduleName": "Example Monitor",
    "scheduleUrl": "https://example.com",
    "screenshotId": "7f3e9a12-...",
    "screenshotUrl": "https://captureze.com/screenshots/...",
    "diffPercent": 5.2,
    "threshold": 5,
    "previousScreenshotId": "3a9f1c44-..."
  }
}

Verifying Signatures

The X-Captureze-Signature header is an HMAC-SHA256 hex digest of the raw JSON request body, signed with your webhook secret:

signature = HMAC-SHA256(secret, JSON.stringify(body))

Always verify the signature before processing a webhook to ensure it came from Captureze:

const crypto = require('crypto');

// IMPORTANT: verify against the raw request body bytes,
// not a re-serialized version — use the express raw-body verify hook.

const express = require('express');
const app = express();

app.post('/webhook',
  express.json({
    verify: (req, _res, buf) => { req.rawBody = buf; }
  }),
  (req, res) => {
    const signature = req.headers['x-captureze-signature'];
    const secret = process.env.WEBHOOK_SECRET;

    if (!signature) {
      return res.status(401).send('Missing signature');
    }

    const expected = crypto
      .createHmac('sha256', secret)
      .update(req.rawBody)
      .digest('hex');

    const sigBuf = Buffer.from(signature, 'hex');
    const expBuf = Buffer.from(expected, 'hex');

    if (sigBuf.length !== expBuf.length ||
        !crypto.timingSafeEqual(sigBuf, expBuf)) {
      return res.status(401).send('Invalid signature');
    }

    const { event, data } = req.body;
    console.log('Received event:', event, data);
    res.sendStatus(200);
  }
);

Important: Parse the body as raw JSON for signature verification — avoid double-serialization. Use express.json() and verify req.body (the already-parsed object), passing it back through JSON.stringify() as shown above.

Retry Policy

If your endpoint returns a non-2xx status code or times out, Captureze will retry:

  • 1st retry: after 1 minute
  • 2nd retry: after 5 minutes
  • 3rd retry: after 30 minutes
  • 4th retry: after 2 hours
  • 5th retry: after 24 hours

After 5 failed attempts the delivery is marked as failed. You can view the full delivery log in Settings → Webhooks → Logs or via GET /api/webhooks/:id/logs.

Best Practices

  • Respond quickly — return 200 within 30 seconds; do heavy work asynchronously
  • Verify signatures — always validate X-Captureze-Signature before processing
  • Deduplicate — use X-Captureze-Delivery to detect duplicate retries
  • HTTPS only — plain HTTP endpoints are not accepted

Testing Webhooks

Use Settings → Webhooks → Send Test or POST /api/webhooks/:id/test to send a sample payload to your endpoint without waiting for a real event.

For local development, tools like webhook.site or ngrok let you receive webhooks on localhost.