Webhooks

Process screenshots asynchronously and receive notifications when they're ready.

How It Works

  1. Send a screenshot request with a webhook URL
  2. Receive immediate response with job ID
  3. Screenshot processes in the background
  4. Receive webhook POST when complete

Configuration

{
  "url": "https://example.com",
  "webhook": {
    "url": "https://your-server.com/webhooks/screenshots",
    "events": ["completed", "failed"],
    "secret": "whsec_xxxxx"
  }
}

Parameters

Parameter Type Default Description
url string Webhook endpoint URL (required)
events array ["completed"] Events to receive
secret string account default Webhook signing secret

Events

Event Description
completed Screenshot captured successfully
failed Screenshot capture failed

Initial Response

When webhook is configured, the request returns immediately:

{
  "id": "job_abc123",
  "status": "processing",
  "webhook": "https://your-server.com/webhooks/screenshots"
}

Webhook Payload

Completed Event

{
  "event": "screenshot.completed",
  "id": "job_abc123",
  "timestamp": "2024-01-18T12:00:00Z",
  "data": {
    "url": "https://example.com",
    "image": {
      "url": "https://cdn.renderscreenshot.com/xyz789.png",
      "width": 1200,
      "height": 630,
      "size": 123456,
      "format": "png"
    },
    "cache": {
      "key": "cache_xyz789",
      "url": "https://cdn.renderscreenshot.com/xyz789.png",
      "expires_at": "2024-01-19T12:00:00Z"
    },
    "metadata": {
      "title": "Example Domain",
      "description": "Example description"
    },
    "usage": {
      "credits": 1,
      "remaining": 9999
    }
  }
}

Failed Event

{
  "event": "screenshot.failed",
  "id": "job_abc123",
  "timestamp": "2024-01-18T12:00:00Z",
  "data": {
    "url": "https://example.com",
    "error": {
      "type": "target_error",
      "code": "timeout",
      "message": "Page failed to load within 30 seconds",
      "retryable": true
    }
  }
}

Webhook Headers

POST /webhooks/screenshots HTTP/1.1
Host: your-server.com
Content-Type: application/json
X-Webhook-ID: whk_abc123
X-Webhook-Timestamp: 1705579200
X-Webhook-Signature: sha256=a1b2c3d4e5f6...
User-Agent: RenderScreenshot-Webhook/1.0

Verifying Signatures

Verify webhook authenticity using the signature:

Ruby

def verify_webhook(payload, signature, timestamp, secret)
  expected = OpenSSL::HMAC.hexdigest(
    'SHA256',
    secret,
    "#{timestamp}.#{payload}"
  )

  Rack::Utils.secure_compare("sha256=#{expected}", signature)
end

# In your controller
signature = request.headers['X-Webhook-Signature']
timestamp = request.headers['X-Webhook-Timestamp']
payload = request.raw_post

if verify_webhook(payload, signature, timestamp, ENV['WEBHOOK_SECRET'])
  # Process webhook
else
  head :unauthorized
end

Node.js

const crypto = require('crypto');

function verifyWebhook(payload, signature, timestamp, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${timestamp}.${payload}`)
    .digest('hex');

  return `sha256=${expected}` === signature;
}

// In your route handler
const signature = req.headers['x-webhook-signature'];
const timestamp = req.headers['x-webhook-timestamp'];
const payload = JSON.stringify(req.body);

if (verifyWebhook(payload, signature, timestamp, process.env.WEBHOOK_SECRET)) {
  // Process webhook
} else {
  res.status(401).send('Invalid signature');
}

Python

import hmac
import hashlib

def verify_webhook(payload, signature, timestamp, secret):
    expected = hmac.new(
        secret.encode(),
        f"{timestamp}.{payload}".encode(),
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(f"sha256={expected}", signature)

Retry Policy

Failed webhook deliveries are retried:

Attempt Delay
1 Immediate
2 1 minute
3 5 minutes
4 30 minutes
5 2 hours

After 5 failed attempts, the webhook is marked as failed.

Responding to Webhooks

Return a 2xx status code to acknowledge receipt:

HTTP/1.1 200 OK

Any non-2xx response triggers a retry.

Batch Webhooks

For batch requests, receive a single webhook when all screenshots complete:

{
  "event": "batch.completed",
  "id": "batch_abc123",
  "timestamp": "2024-01-18T12:00:00Z",
  "data": {
    "summary": {
      "total": 10,
      "completed": 9,
      "failed": 1
    },
    "results_url": "https://api.renderscreenshot.com/v1/batch/batch_abc123/results"
  }
}

Common Patterns

Async Social Card Generation

{
  "url": "https://myblog.com/post/123",
  "preset": "og_card",
  "webhook": {
    "url": "https://myblog.com/api/webhooks/og-image",
    "events": ["completed", "failed"]
  }
}

Background Processing Pipeline

{
  "url": "https://example.com",
  "webhook": {
    "url": "https://api.myservice.com/process-screenshot",
    "secret": "whsec_custom_secret"
  },
  "storage": {
    "enabled": true
  }
}

Examples

Request with Webhook

curl -X POST https://api.renderscreenshot.com/v1/screenshot \
  -H "Authorization: Bearer rs_live_xxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "preset": "og_card",
    "webhook": {
      "url": "https://myserver.com/webhooks/screenshots",
      "events": ["completed", "failed"]
    }
  }'

Response:

{
  "id": "job_abc123",
  "status": "processing",
  "webhook": "https://myserver.com/webhooks/screenshots"
}

Testing Webhooks

Use tools like webhook.site or ngrok to test webhooks locally.

See Also

Was this page helpful?