TLDR: GetCookies webhooks deliver real-time consent events to your systems via HTTP POST. 15+ event types, HMAC-SHA256 signing, automatic retries, and delivery tracking. Sync consent to your CRM, trigger marketing automation, and build custom workflows.
Read full summary
Complete guide to GetCookies webhook integration for real-time consent event delivery. Covers all supported event types (consent, domain, scan, compliance), payload structure, security with HMAC signing, retry logic, and practical use cases including CRM sync, marketing automation triggers, and compliance audit logging.
*Summary by Claude AI*
## The Real-Time Consent Problem
A DTC e-commerce brand had a sophisticated marketing stack: Klaviyo for email, Attentive for SMS, Meta Ads for retargeting. Each platform needed to know user consent status. But consent was collected in the browser, and these platforms lived server-side.
Their solution: batch export consent records once per day. The result: 24 hours of potential violations. Marketing messages went to users who had rejected consent. Retargeting pixels targeted people who had opted out.
Real-time consent requires real-time data flow. Batch processing is a compliance gap waiting to happen.
## Why Webhooks for Consent
### Immediate Action
When a user withdraws consent, your systems should know instantly—not tomorrow morning.
### No Polling Required
Webhook push is more efficient than repeatedly asking "any new consents?" Reduce API calls, reduce latency.
### Event-Driven Architecture
Modern systems are event-driven. Webhooks let consent changes trigger downstream workflows immediately.
### Audit Trail
Webhook deliveries are logged. You can prove when you were notified and how quickly you acted.
## GetCookies Webhook Events
### Consent Events
| Event | Description | When Triggered |
|-------|-------------|----------------|
| `consent.accepted` | User accepted consent | Banner interaction |
| `consent.rejected` | User rejected consent | Banner interaction |
| `consent.updated` | Preferences changed | Settings update |
| `consent.withdrawn` | Consent revoked | Settings or GPC signal |
### Domain Events
| Event | Description | When Triggered |
|-------|-------------|----------------|
| `domain.created` | New domain added | Dashboard action |
| `domain.updated` | Domain config changed | Settings save |
| `domain.deleted` | Domain removed | Deletion confirmed |
| `domain.verified` | Ownership confirmed | DNS verification |
### Scan Events
| Event | Description | When Triggered |
|-------|-------------|----------------|
| `scan.started` | Cookie scan began | Manual or scheduled |
| `scan.completed` | Scan finished | Scan completion |
| `scan.failed` | Scan error occurred | Error state |
### Compliance Events
| Event | Description | When Triggered |
|-------|-------------|----------------|
| `compliance.violation_detected` | Issue found | Post-scan analysis |
| `compliance.audit_generated` | Report ready | Audit completion |
## Webhook Payload Structure
### Standard Payload
```json
{
"id": "evt_abc123xyz",
"type": "consent.accepted",
"timestamp": "2025-01-15T14:32:00Z",
"domain_id": "550e8400-e29b-41d4-a716-446655440000",
"data": {
"visitor_id": "v_xyz789",
"consent_categories": {
"essential": true,
"analytics": true,
"marketing": false,
"personalization": false
},
"consent_version": "2.1",
"gpc_enabled": false,
"user_agent": "Mozilla/5.0...",
"ip_country": "DE"
}
}
```
### Consent-Specific Fields
```json
{
"data": {
"previous_consent": {
"analytics": false,
"marketing": false
},
"new_consent": {
"analytics": true,
"marketing": false
},
"consent_method": "banner",
"consent_duration": 3400, // ms until decision
"tc_string": "CPA..." // if TCF enabled
}
}
```
### Global Privacy Control (GPC) Fields
Every consent webhook now includes GPC information for audit-ready compliance logging:
```json
{
"data": {
"gpc": {
"signal_detected": true,
"honored": true,
"consent_source": "gpc_auto",
"region_code": "US-CA"
}
}
}
```
| Field | Type | Description |
|-------|------|-------------|
| `signal_detected` | boolean | Whether browser sent GPC signal (`navigator.globalPrivacyControl` or `Sec-GPC` header) |
| `honored` | boolean | Whether the opt-out was applied based on the signal |
| `consent_source` | string | How consent was obtained: `banner`, `gpc_auto`, `api`, `account_settings` |
| `region_code` | string | Jurisdiction code (e.g., `US-CA`, `EU`, `GB`) for compliance context |
**Why this matters:** 12+ US states now require honoring GPC as a legally binding opt-out signal, including California, Colorado, Connecticut, Texas, Oregon, Montana, Delaware, New Jersey, New Hampshire, Nebraska, Minnesota, and Maryland. These fields let you prove you detected and honored the signal for audit purposes.
### Do Not Track (DNT) Fields
We also detect and log the legacy DNT signal for completeness:
```json
{
"data": {
"dnt": {
"signal_detected": true,
"honored": true
}
}
}
```
| Field | Type | Description |
|-------|------|-------------|
| `signal_detected` | boolean | Whether browser sent DNT signal (`navigator.doNotTrack`) |
| `honored` | boolean | Whether the signal was honored (not legally required but good faith) |
**Note:** DNT is not legally binding anywhere, but some organizations still honor it as a good faith privacy measure.
## Security: HMAC Signing
Every webhook is signed with HMAC-SHA256. Verify to ensure authenticity.
### Signature Header
```
X-GetCookies-Signature: sha256=a3f9b2c1d8e7...
```
### Verification Code
**Node.js:**
```javascript
const crypto = require('crypto');
function verifySignature(payload, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your webhook handler
app.post('/webhooks/consent', (req, res) => {
const signature = req.headers['x-getcookies-signature'];
const isValid = verifySignature(
JSON.stringify(req.body),
signature,
process.env.WEBHOOK_SECRET
);
if (!isValid) {
return res.status(401).send('Invalid signature');
}
// Process event...
res.status(200).send('OK');
});
```
**Python:**
```python
import hmac
import hashlib
def verify_signature(payload: bytes, signature: str, secret: str) -> bool:
expected = 'sha256=' + hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
```
## Retry Logic
Failed deliveries are retried with exponential backoff:
| Attempt | Delay |
|---------|-------|
| 1 | Immediate |
| 2 | 30 seconds |
| 3 | 2 minutes |
| 4 | 10 minutes |
| 5 | 1 hour |
After 5 failures, the webhook is marked as failing. You'll receive an email notification.
### Delivery Status
Each webhook tracks:
- Delivery attempts
- Response codes
- Response times
- Error messages
View history in your dashboard or via API.
## Creating Webhooks
### Via Dashboard
1. Go to **Settings > Webhooks**
2. Click **Add Webhook**
3. Enter endpoint URL
4. Select events to subscribe
5. Copy the signing secret
6. Click **Create**
### Via API
```bash
curl -X POST https://api.getcookies.co/v1/webhooks \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"domain_id": "550e8400-e29b-41d4-a716-446655440000",
"name": "CRM Sync",
"url": "https://your-api.com/webhooks/consent",
"events": ["consent.accepted", "consent.updated", "consent.withdrawn"],
"retry_enabled": true,
"retry_max_attempts": 5
}'
```
## Use Case: CRM Consent Sync
### HubSpot Integration
```javascript
app.post('/webhooks/consent', async (req, res) => {
const { type, data } = req.body;
if (type === 'consent.accepted' || type === 'consent.updated') {
// Find or create contact by visitor ID
const contact = await hubspot.contacts.getByProperty(
'getcookies_visitor_id',
data.visitor_id
);
// Update consent properties
await hubspot.contacts.update(contact.id, {
properties: {
analytics_consent: data.consent_categories.analytics,
marketing_consent: data.consent_categories.marketing,
consent_updated_at: data.timestamp,
consent_version: data.consent_version
}
});
}
res.status(200).send('OK');
});
```
### Salesforce Integration
```javascript
if (type === 'consent.withdrawn') {
// Immediately update Salesforce contact
await salesforce.sobjects.Contact.update({
Id: contactId,
GDPR_Consent__c: false,
Marketing_Consent__c: false,
Consent_Withdrawal_Date__c: new Date().toISOString()
});
// Remove from marketing campaigns
await salesforce.sobjects.CampaignMember.delete({
ContactId: contactId
});
}
```
## Use Case: Marketing Automation
### Email Suppression
```javascript
if (type === 'consent.rejected' || type === 'consent.withdrawn') {
// Add to suppression list immediately
await klaviyo.profiles.suppress({
email: data.email,
reason: 'consent_withdrawn'
});
// Stop any active flows
await klaviyo.flows.cancelForProfile(data.email);
}
```
### Segment User Updates
```javascript
// Update Segment traits in real-time
analytics.identify(data.visitor_id, {
analytics_consent: data.consent_categories.analytics,
marketing_consent: data.consent_categories.marketing,
consent_source: 'getcookies_webhook'
});
```
## Use Case: Compliance Logging
### Immutable Audit Trail
```javascript
// Write to append-only compliance log
await complianceLog.append({
event_id: req.body.id,
event_type: req.body.type,
timestamp: req.body.timestamp,
visitor_id: req.body.data.visitor_id,
consent_state: req.body.data.consent_categories,
raw_payload: JSON.stringify(req.body),
received_at: new Date().toISOString()
});
```
### Datadog Event
```javascript
// Send compliance events to monitoring
dogstatsd.event({
title: `Consent ${req.body.type.split('.')[1]}`,
text: JSON.stringify(req.body.data.consent_categories),
tags: [
`domain:${req.body.domain_id}`,
`country:${req.body.data.ip_country}`,
`event_type:${req.body.type}`
]
});
```
## Use Case: Slack Notifications
```javascript
if (type === 'compliance.violation_detected') {
await slack.postMessage({
channel: '#compliance-alerts',
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `⚠️ *Compliance Violation Detected*\n\nDomain: ${data.domain}\nIssue: ${data.violation_type}\nSeverity: ${data.severity}`
}
},
{
type: 'actions',
elements: [{
type: 'button',
text: { type: 'plain_text', text: 'View Details' },
url: `https://app.getcookies.co/domains/${data.domain_id}/compliance`
}]
}
]
});
}
```
## Testing Webhooks
### Test Endpoint
Send a test event from the dashboard:
1. Go to **Settings > Webhooks**
2. Click **...** menu on your webhook
3. Select **Send Test Event**
4. Choose event type
5. View delivery result
### Local Development
Use ngrok or similar to expose local endpoints:
```bash
ngrok http 3000
# Use the generated URL for webhook testing
```
### Webhook Debugging
Check the delivery log for:
- Request payload sent
- Response code received
- Response body (if any)
- Timing information
## Best Practices
### Respond Quickly
Return 200 immediately, then process asynchronously:
```javascript
app.post('/webhooks/consent', async (req, res) => {
// Acknowledge immediately
res.status(200).send('OK');
// Process in background
processWebhook(req.body).catch(err => {
console.error('Webhook processing failed:', err);
});
});
```
### Handle Duplicates
Network issues can cause duplicate deliveries. Use event ID for idempotency:
```javascript
const processed = await cache.get(`webhook:${req.body.id}`);
if (processed) return res.status(200).send('Already processed');
await cache.set(`webhook:${req.body.id}`, true, 86400);
// Process event...
```
### Monitor Failures
Set up alerts for webhook failures to catch issues early.
## Getting Started
1. Create a webhook endpoint in your application
2. Register it in GetCookies dashboard
3. Implement signature verification
4. Handle the event types you need
5. Test with sample events
6. Monitor delivery success
Real-time consent data enables real-time compliance. Webhooks make it possible.