Menu
webhooksintegrationstutorial

Real-Time Screenshot Notifications with Webhooks

SnapSharp Team·March 25, 2026·5 min read

Real-Time Screenshot Notifications with Webhooks

Instead of polling for results, let SnapSharp push notifications to you. Webhooks fire when screenshots complete, requests fail, or your usage hits a threshold.

What you can subscribe to

EventWhen it fires
screenshot.completedAny successful screenshot, OG image, or HTML-to-image request
screenshot.failedA request failed (timeout, unreachable URL, etc.)
usage.threshold.80Monthly usage hit 80% of your plan limit
usage.threshold.100Monthly usage hit 100% — requests will be rejected

Setting up webhooks

  1. Go to Dashboard → Settings → Webhooks
  2. Enter your endpoint URL (must be HTTPS)
  3. Select which events you want
  4. Save — copy the webhook secret (shown once)

Building a webhook handler

Here's a minimal Express.js handler that verifies the signature and processes events:

import express from 'express';
import crypto from 'crypto';

const app = express();
app.use(express.raw({ type: 'application/json' }));

const WEBHOOK_SECRET = process.env.SNAPSHARP_WEBHOOK_SECRET!;

app.post('/webhooks/snapsharp', (req, res) => {
  const signature = req.headers['x-webhook-signature'] as string;
  const expected = 'sha256=' + crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(req.body)
    .digest('hex');

  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
    return res.status(401).send('Invalid signature');
  }

  const payload = JSON.parse(req.body.toString());

  switch (payload.event) {
    case 'screenshot.completed':
      console.log(`Screenshot done: ${payload.data.url} (${payload.data.response_time_ms}ms)`);
      break;
    case 'screenshot.failed':
      console.error(`Screenshot failed: ${payload.data.url} — ${payload.data.error_message}`);
      break;
    case 'usage.threshold.80':
      console.warn(`Usage at ${payload.data.percentage}% — consider upgrading`);
      break;
    case 'usage.threshold.100':
      console.error('Monthly limit reached!');
      break;
  }

  res.status(200).send('OK');
});

Payload structure

Every webhook delivers a JSON payload:

{
  "event": "screenshot.completed",
  "timestamp": "2026-03-25T14:30:00.000Z",
  "data": {
    "request_id": "550e8400-e29b-41d4-a716-446655440000",
    "endpoint": "/v1/screenshot",
    "url": "https://example.com",
    "status_code": 200,
    "response_time_ms": 1247,
    "cached": false
  }
}

Security: always verify signatures

Every webhook request includes an X-Webhook-Signature header with an HMAC-SHA256 hash. Always verify it before processing — this confirms the request came from SnapSharp, not an attacker.

Automatic retries

If your endpoint returns a non-2xx status or doesn't respond within 10 seconds, SnapSharp retries:

  • Attempt 1: Immediate
  • Attempt 2: After 30 seconds
  • Attempt 3: After 5 minutes
  • Attempt 4 (final): After 1 hour

After all retries fail, the delivery is marked as failed. Check delivery history in the dashboard.

Use cases

  • Slack/Discord notifications — post to a channel when screenshots fail
  • Monitoring dashboards — track success rates and response times
  • Usage alerts — get warned before hitting your monthly limit
  • Pipeline triggers — kick off downstream processing when a screenshot is ready
  • Error tracking — log failed screenshots to Sentry or your error tracker

Testing

Use the Test button next to any webhook in the dashboard to send a sample payload and verify your endpoint works.

Full webhook docs: snapsharp.dev/docs/webhooks