Webhooks
Webhooks allow you to receive real-time notifications when scraping operations complete, fail, or start. Instead of polling for results, configure a webhook endpoint to receive instant updates about your scraping jobs.
Overview
Webhooks are HTTP callbacks that deliver event notifications to your configured URL. Use webhooks to:
- Get notified when scrapes complete — Receive results automatically
- Handle failures gracefully — React to errors in real-time
- Integrate with chat platforms — Send notifications to Discord or Slack
- Build event-driven workflows — Trigger downstream processes automatically
Supported Platforms
| Platform | Description |
|---|---|
| Discord | Send rich embeds to Discord channels via webhook URLs |
| Slack | Post messages to Slack channels using incoming webhooks |
| Custom | Send JSON payloads to any HTTP endpoint with HMAC signature verification |
Webhook Configuration
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
url |
string | Yes | Your webhook endpoint URL |
type |
string | Yes | Webhook type: "discord", "slack", or "custom" |
events |
array | Yes | List of events to subscribe to |
secret |
string | No | Secret key for HMAC signature (custom webhooks only) |
Available Events
| Event | Description |
|---|---|
started |
Job has been queued and started |
completed |
Job finished successfully |
failed |
Job encountered an error and failed |
Usage Examples
With Scrape Requests
curl -X POST "https://scrape.evomi.com/api/v1/scraper/realtime" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"mode": "browser",
"webhook": {
"url": "https://your-server.com/webhook",
"type": "custom",
"events": ["completed", "failed"],
"secret": "your-secret-key"
}
}'With Crawl Requests
curl -X POST "https://scrape.evomi.com/api/v1/scraper/crawl" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"domain": "example.com",
"max_urls": 100,
"webhook": {
"url": "https://discord.com/api/webhooks/...",
"type": "discord",
"events": ["completed"]
}
}'With Map Requests
curl -X POST "https://scrape.evomi.com/api/v1/scraper/map" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"domain": "example.com",
"sources": ["sitemap", "commoncrawl"],
"webhook": {
"url": "https://hooks.slack.com/services/...",
"type": "slack",
"events": ["completed", "failed"]
}
}'With Search Requests
curl -X POST "https://scrape.evomi.com/api/v1/scraper/search" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "e-commerce platforms",
"max_urls": 20,
"webhook": {
"url": "https://your-server.com/webhook",
"type": "custom",
"events": ["completed"]
}
}'With Schedules
curl -X POST "https://scrape.evomi.com/api/v1/account/schedule" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Daily Price Monitor",
"config_id": "cfg_abc123",
"interval_minutes": 1440,
"webhook": {
"url": "https://discord.com/api/webhooks/...",
"type": "discord",
"events": ["completed", "failed"]
}
}'Platform-Specific Integration
Discord Webhooks
Discord webhooks post rich embeds to a channel. Get your webhook URL from channel settings:
- Go to Channel Settings → Integrations → Webhooks
- Click New Webhook and copy the URL
# Discord webhook example
"webhook": {
"url": "https://discord.com/api/webhooks/123456789/abc123...",
"type": "discord",
"events": ["completed", "failed"]
}Discord embeds include:
- Job status with color coding (green for success, red for failure)
- URL scraped
- Credits used
- Timestamp
Slack Webhooks
Slack webhooks post messages using incoming webhook URLs. Create one in your Slack app:
- Create a Slack App or use an existing one
- Enable Incoming Webhooks
- Create a new webhook URL
# Slack webhook example
"webhook": {
"url": "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXX",
"type": "slack",
"events": ["completed"]
}Slack messages include:
- Status emoji (✅ or ❌)
- Job details in attachment format
- Link to view results
Custom Webhooks
Custom webhooks send JSON payloads to any HTTP endpoint. Use the secret parameter for HMAC signature verification:
# Custom webhook with HMAC signature
"webhook": {
"url": "https://your-server.com/api/webhooks/evomi",
"type": "custom",
"events": ["started", "completed", "failed"],
"secret": "your-webhook-secret"
}Payload Structure
Custom Webhook Payload
When using custom webhooks, Evomi sends a POST request with the following JSON structure:
{
"event": "completed",
"timestamp": "2026-03-09T12:00:00Z",
"data": {
"task_id": "task_abc123",
"task_type": "scrape",
"url": "https://example.com",
"status": "success",
"credits_used": 5,
"result": {
"content": "...",
"metadata": {}
}
}
}Payload Fields
| Field | Type | Description |
|---|---|---|
event |
string | Event type: started, completed, or failed |
timestamp |
string | ISO 8601 timestamp of the event |
data.task_id |
string | Unique identifier for the task |
data.task_type |
string | Type: scrape, crawl, map, or search |
data.url |
string | URL that was scraped (for scrape tasks) |
data.status |
string | success or failed |
data.credits_used |
number | Credits consumed by the operation |
data.result |
object | Scraping results (for completed events) |
data.error |
string | Error message (for failed events) |
HMAC Signature Verification
For custom webhooks, verify the request authenticity using HMAC-SHA256 signatures.
How It Works
- Evomi creates a signature using your
secretand the request body - The signature is sent in the
X-Evomi-Signatureheader - Your server verifies the signature before processing
Verification Example (Node.js)
const crypto = require('crypto');
function verifyWebhook(req, secret) {
const signature = req.headers['x-evomi-signature'];
const payload = JSON.stringify(req.body);
const expectedSignature = 'sha256=' +
crypto.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return signature === expectedSignature;
}
// Usage
app.post('/webhooks/evomi', (req, res) => {
if (!verifyWebhook(req, 'your-webhook-secret')) {
return res.status(401).send('Invalid signature');
}
// Process webhook
console.log('Event:', req.body.event);
res.status(200).send('OK');
});Verification Example (Python)
import hmac
import hashlib
import json
def verify_webhook(headers, body, secret):
signature = headers.get('X-Evomi-Signature', '')
expected = 'sha256=' + hmac.new(
secret.encode(),
json.dumps(body).encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
# Usage in Flask
@app.route('/webhooks/evomi', methods=['POST'])
def handle_webhook():
if not verify_webhook(request.headers, request.json, 'your-webhook-secret'):
return 'Invalid signature', 401
# Process webhook
event = request.json.get('event')
print(f'Event: {event}')
return 'OK', 200Best Practices
1. Respond Quickly
Return a 200 OK response within 5 seconds. Long-running processes should be handled asynchronously:
@app.route('/webhook', methods=['POST'])
def webhook():
# Queue the work for background processing
process_webhook_async.delay(request.json)
return 'OK', 2002. Implement Retry Logic
If your endpoint is temporarily unavailable, Evomi will retry:
- Up to 5 attempts
- Exponential backoff
- 24-hour retention
3. Verify Signatures
Always verify HMAC signatures for custom webhooks to ensure requests come from Evomi.
4. Handle Duplicate Events
Events may be delivered more than once. Use the task_id to deduplicate:
processed_tasks = set()
def handle_webhook(payload):
task_id = payload['data']['task_id']
if task_id in processed_tasks:
return # Already processed
processed_tasks.add(task_id)
# Process the event5. Use HTTPS
Webhook URLs must use HTTPS with a valid SSL certificate.
Troubleshooting
Webhooks Not Received
- Check firewall settings — Ensure your server accepts connections from Evomi IPs
- Verify SSL certificate — HTTPS is required with a valid certificate
- Review server logs — Look for incoming requests from Evomi
- Test manually — Use curl to test your endpoint
Test Your Endpoint
curl -X POST "https://your-server.com/webhook" \
-H "Content-Type: application/json" \
-H "X-Evomi-Signature: sha256=..." \
-d '{
"event": "completed",
"timestamp": "2026-03-09T12:00:00Z",
"data": {
"task_id": "test_123",
"task_type": "scrape",
"status": "success"
}
}'What’s Next?
- Schedules — Create scheduled scraping jobs
- Scraper Configs — Save reusable configurations
- Usage Examples — See complete code examples