Receiving webhook notifications
The GitBook Webhook Integration allows you to receive real-time notifications when events occur in your GitBook spaces. This integration supports configurable webhook URL, HMAC signature verification, and automatic retry logic with exponential backoff.
Features
Real-time Event Delivery: Receive instant notifications for selected events
HMAC Signature Verification: Secure webhook delivery with cryptographic verification
Automatic Retry Logic: Built-in retry mechanism with exponential backoff for failed deliveries
Configurable Events: Choose which events to receive (site views, content updates, page feedback)
Supported Events
Site View Events (site_view
)
site_view
)Triggered when a user visits a page on your GitBook site.
Payload Example:
{
"eventId": "evt_1234567890abcdef",
"type": "site_view",
"siteId": "site_abc123",
"installationId": "inst_def456",
"visitor": {
"anonymousId": "anon_789ghi",
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
"ip": "192.168.1.100",
"cookies": {
"session_id": "sess_xyz789"
}
},
"url": "https://docs.example.com/getting-started",
"referrer": "https://www.google.com/search?q=example+docs"
}
Content Updated Events (space_content_updated
)
space_content_updated
)Triggered when content in a space is modified.
Payload Example:
{
"eventId": "evt_2345678901bcdefg",
"type": "space_content_updated",
"spaceId": "space_xyz789",
"installationId": "inst_def456",
"revisionId": "rev_abc123def456"
}
Page Feedback Events (page_feedback
)
page_feedback
)Triggered when users provide feedback on pages.
Payload Example:
{
"eventId": "evt_3456789012cdefgh",
"type": "page_feedback",
"siteId": "site_abc123",
"spaceId": "space_xyz789",
"installationId": "inst_def456",
"pageId": "page_feedback123",
"feedback": {
"rating": "good",
"comment": "This page was very helpful!"
},
"visitor": {
"anonymousId": "anon_789ghi",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"ip": "192.168.1.101",
"cookies": {}
},
"url": "https://docs.example.com/api-reference",
"referrer": "https://docs.example.com/getting-started"
}
Configuration
Required Settings
Webhook URL: The endpoint where events will be sent
Event Types: Select which events to receive
Webhook Security
HMAC Signature Verification
All webhook requests include an HMAC-SHA256 signature in the X-GitBook-Signature
header for verification.
Header Format:
X-GitBook-Signature: t=1640995200,v1=abc123def456...
Where:
t
: Unix timestamp of the requestv1
: HMAC-SHA256 signature of the payload
Signature Verification Example
const crypto = require('crypto');
function verifyGitBookSignature(payload, signature, secret) {
if (!signature) return false;
try {
// Parse signature format: t=timestamp,v1=hash
const parts = signature.split(',');
let timestamp, hash;
for (const part of parts) {
if (part.startsWith('t=')) {
timestamp = part.substring(2);
} else if (part.startsWith('v1=')) {
hash = part.substring(3);
}
}
if (!timestamp || !hash) return false;
// Generate expected signature (our implementation uses timestamp.payload format)
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${payload}`)
.digest('hex');
// Constant-time comparison to prevent timing attacks
return crypto.timingSafeEqual(
Buffer.from(hash, 'hex'),
Buffer.from(expectedSignature, 'hex')
);
} catch (error) {
return false;
}
}
// Usage
const isValid = verifyGitBookSignature(
requestBody,
request.headers['x-gitbook-signature'],
'your-secret-key'
);
Retry Logic
The integration includes automatic retry logic for failed webhook deliveries:
Max Retries: 3 attempts
Backoff Strategy: Exponential backoff with jitter
Base Delay: 1 second
Jitter: ±10% of base delay
Retry Conditions:
Network errors (timeouts, connection refused)
Server errors (5xx status codes)
Rate limiting (429 status codes)
No Retry: Client errors (4xx except 429)
Retry Schedule Example
1
1s
±0.1s
1.0-1.1s
1s
2
2s
±0.2s
2.0-2.2s
2s
3
4s
±0.4s
4.0-4.4s
4s
Error Handling
HTTP Status Codes
200: Success
400: Bad Request (client error, no retry)
429: Too Many Requests (rate limited, will retry)
500: Internal Server Error (server error, will retry)
Best Practices
1. Webhook Endpoint Design
const express = require('express');
const crypto = require('crypto');
const app = express();
// Express.js example
app.post('/webhooks/gitbook', express.raw({type: 'application/json'}), (req, res) => {
// Get raw body as string for signature verification
const requestBody = req.body.toString();
// Verify signature first
const signature = req.headers['x-gitbook-signature'];
const isValid = verifyGitBookSignature(requestBody, signature, process.env.GITBOOK_SECRET);
if (!isValid) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Parse and process event
const event = JSON.parse(requestBody);
switch (event.type) {
case 'site_view':
handleSiteView(event);
break;
case 'space_content_updated':
handleContentUpdate(event);
break;
case 'page_feedback':
handlePageFeedback(event);
break;
}
res.status(200).json({ received: true });
});
2. Idempotency
Handle duplicate events gracefully:
const express = require('express');
const crypto = require('crypto');
const app = express();
const processedEvents = new Map();
const EVENT_RETENTION_MS = 2 * 60 * 1000; // 2 minutes
function remember(eventId) {
if (processedEvents.has(eventId)) return false;
// Insert and schedule automatic eviction
const timer = setTimeout(() => {
processedEvents.delete(eventId);
}, EVENT_RETENTION_MS);
processedEvents.set(eventId, timer);
return true;
}
function handleEvent(event) {
// Guard goes first so concurrent deliveries don’t double-process
if (!remember(event.eventId)) {
console.log('Duplicate event ignored:', event.eventId);
return;
}
// Process event...
// doWork(event);
// If processing fails and you want to allow a retry, you can undo the remember:
// clearTimeout(processedEvents.get(event.eventId));
// processedEvents.delete(event.eventId);
}
3. Async Processing
Process events asynchronously to respond quickly:
const express = require('express');
const crypto = require('crypto');
const app = express();
app.post('/webhooks/gitbook', express.raw({type: 'application/json'}), (req, res) => {
// Get raw body as string for signature verification
const requestBody = req.body.toString();
// Verify signature
const signature = req.headers['x-gitbook-signature'];
const isValid = verifyGitBookSignature(requestBody, signature, process.env.GITBOOK_SECRET);
if (!isValid) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Respond immediately
res.status(200).json({ received: true });
// Process asynchronously
setImmediate(() => {
const event = JSON.parse(requestBody);
processEvent(event);
});
});
Last updated
Was this helpful?