Automation: Webhooks & Translations

Configure once, runs automatically. Stream consent events to your backend and serve the banner in regional languages required by the DPDP Act.

Webhooks

Webhooks push consent-lifecycle events to your backend the moment they happen, so you can keep CRMs, analytics, support tools, and audit systems in sync without polling.

Events

EventFired when
purpose.grantedThe user grants consent for a purpose (banner or layered prompt).
purpose.deniedThe user explicitly denies consent for a purpose.
purpose.withdrawnThe user withdraws a previously granted consent (via preferences modal or DSR).
purpose.expiredA consent record passes its retention window and is auto-expired.

Setup

  1. 1
    Go to Admin → Cookies → Automation → Webhooks and click Add Webhook.
  2. 2
    Paste your endpoint URL (must be https://) and tick the events you want to receive.
  3. 3
    On save, a one-time signing secret is shown. Copy it and store it as an env var on your backend — you cannot retrieve it later.
  4. 4
    Use the Send test event button on the webhook row to verify your endpoint is wired correctly.

Payload shape

POST https://your-endpoint.com/privacy-labs
Content-Type: application/json
X-PrivacyLabs-Event: purpose.granted
X-PrivacyLabs-Timestamp: 1714915200
X-PrivacyLabs-Signature: sha256=<hex-hmac-sha256>

{
  "event": "purpose.granted",
  "timestamp": 1714915200,
  "data": {
    "purposeKey": "marketing_emails",
    "sessionId": "...",
    "platform": "web",
    "occurredAt": "2026-05-07T11:22:33.123Z"
  }
}

Verifying the signature (recommended)

Compute an HMAC-SHA256 over <timestamp>.<raw-body> using your signing secret, and compare it (constant-time) against the hex value after sha256= in the X-PrivacyLabs-Signature header. Reject anything older than 5 minutes to block replay attacks.

import crypto from 'crypto';

function verify(rawBody, headers, secret) {
  const timestamp = headers['x-privacylabs-timestamp'];
  const sigHeader = headers['x-privacylabs-signature']; // "sha256=<hex>"
  const received = sigHeader.replace('sha256=', '');

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

  const ageSec = (Date.now() / 1000) - Number(timestamp);
  if (ageSec > 300) return false; // 5 minute replay window

  return crypto.timingSafeEqual(
    Buffer.from(expected, 'hex'),
    Buffer.from(received, 'hex')
  );
}

Retries & auto-disable

  • Any non-2xx response is treated as a failure. We retry with exponential back-off.
  • Respond 200 OK within 5 seconds. We don't wait longer than that.
  • After 10 consecutive failures, the webhook is auto-disabled and shown as such in the dashboard. Re-enable it once your endpoint is healthy.
  • Handlers should be idempotent — the same event may be delivered more than once after retries. Use data.recordId as the dedupe key.

HTTPS only. Plain HTTP endpoints are rejected at save time. Use a real cert (not self-signed) — many cloud webhooks won't trust self-signed CAs.

Translations

The DPDP Act requires consent notices to be available in the user's regional language (Eighth Schedule). Add languages once — the banner auto-detects the user's locale and shows the right one.

Workflow

  1. 1
    Go to Admin → Cookies → Automation → Translations and pick the languages you need from the chips.
  2. 2
    Click Generate Translations. The engine translates every banner string from your English source.
  3. 3
    Open each language row, click Edit, and review. Saving promotes the status from auto-translated to reviewed.
  4. 4
    Toggle Active on the languages you want live. The SDK begins serving them immediately to matching users.

When the source text changes

If you edit your English banner copy (title, description, button labels) the existing translations don't update automatically. Use the Re-translate All button to refresh every language from the latest English source. Your manual edits will be overwritten, so do this when you genuinely want a fresh translation.

What gets translated

All visible banner strings: title, description, accept/settings/save buttons, withdraw-consent link, privacy-policy link, and the four standard category names with descriptions (essential, performance, analytics, marketing).

Purpose names and descriptions you define under Consent Data are translated separately at the purpose level. (Recommended: write purpose copy in clear, neutral English; the auto-translator handles regional variants better that way.)

Related docs