Webhooks
Sockudo sends webhooks to notify your backend when channel and presence events occur. Webhooks are Pusher-compatible - the same payload format, signing mechanism, and event types.
How It Works
- An event occurs (channel occupied, member joined, client event, etc.).
- Sockudo matches the event against your app's webhook definitions.
- A job is pushed to the queue.
- Queue workers dispatch HTTP requests (or Lambda invocations) asynchronously.
This means webhook delivery never blocks WebSocket message handling.
Configuring Webhooks
Webhooks are defined per-app in the webhooks field:
{
"app_manager": {
"driver": "memory",
"array": {
"apps": [
{
"id": "my-app",
"key": "my-key",
"secret": "my-secret",
"enabled": true,
"webhooks": [
{
"url": "https://your-backend.com/webhooks/sockudo",
"event_types": ["channel_occupied", "channel_vacated", "member_added", "member_removed"]
}
]
}
]
}
}
}
Event Types
| Event | Trigger |
|---|---|
channel_occupied | First subscriber joins a channel |
channel_vacated | Last subscriber leaves a channel |
member_added | User joins a presence channel |
member_removed | User leaves a presence channel |
client_event | Client sends an event on a private/presence channel |
Webhook Payload
Sockudo sends a JSON payload compatible with the Pusher webhook format:
{
"time_ms": 1707744000000,
"events": [
{
"name": "channel_occupied",
"channel": "presence-chat"
}
]
}
For presence events, additional fields are included:
{
"time_ms": 1707744000000,
"events": [
{
"name": "member_added",
"channel": "presence-chat",
"user_id": "user-123"
}
]
}
Request Signing
Each webhook request includes headers for verification:
| Header | Description |
|---|---|
Content-Type | application/json |
X-Pusher-Key | Your app key |
X-Pusher-Signature | HMAC-SHA256 hex digest of the body, signed with your app secret |
Verifying Signatures
On your backend, verify the signature to ensure the request came from Sockudo:
const crypto = require('crypto');
function verifyWebhook(body, signature, appSecret) {
const expected = crypto
.createHmac('sha256', appSecret)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
Webhook Filtering
You can filter which channels trigger a webhook using the filter field:
{
"webhooks": [
{
"url": "https://backend.com/presence-hooks",
"event_types": ["member_added", "member_removed"],
"filter": {
"channel_prefix": "presence-"
}
},
{
"url": "https://backend.com/chat-hooks",
"event_types": ["channel_occupied", "channel_vacated"],
"filter": {
"channel_prefix": "private-chat-"
}
}
]
}
| Filter Field | Description |
|---|---|
channel_prefix | Only match channels starting with this string |
channel_suffix | Only match channels ending with this string |
channel_pattern | Regex pattern to match channel names |
Custom Headers
Add custom headers to webhook requests for authentication or routing:
{
"webhooks": [
{
"url": "https://backend.com/hooks",
"event_types": ["channel_occupied"],
"headers": {
"Authorization": "Bearer my-token",
"X-Custom-Header": "value"
}
}
]
}
Lambda Webhooks
Instead of HTTP endpoints, you can invoke AWS Lambda functions directly:
{
"webhooks": [
{
"lambda": {
"function_name": "my-webhook-handler",
"region": "us-east-1"
},
"event_types": ["channel_occupied", "channel_vacated"]
}
]
}
lambda feature flag at compile time.Batching
Sockudo can batch multiple events into a single webhook delivery to reduce HTTP overhead:
{
"webhooks": {
"batching": {
"enabled": true,
"duration": 50
}
}
}
| Setting | Env Var | Default | Description |
|---|---|---|---|
enabled | WEBHOOK_BATCHING_ENABLED | true | Enable batching |
duration | WEBHOOK_BATCHING_DURATION | 50 | Batch window in milliseconds |
When batching is enabled, events are collected for duration ms before being dispatched as a single job. This means a burst of channel events (e.g., multiple users joining at once) gets sent as one webhook request with multiple events in the events array.
Delivery Guarantees
- Timeout: 10 seconds per webhook HTTP request.
- Concurrency: Up to 20 concurrent webhook dispatches.
- Retry: Depends on the queue driver:
- Redis: Jobs are removed from the queue on consumption. Failed deliveries are not automatically retried.
- SQS: Failed messages become visible again after
visibility_timeout, providing automatic retry.
- Deduplication: Jobs include a signature to prevent duplicate processing.
Disabling Webhooks
Set the queue driver to none to disable webhook processing entirely:
QUEUE_DRIVER=none
Or simply don't define any webhooks in your app configuration.