Docs

JavaScript SDK

Install, client, methods, tag gate, double opt-in and receipt verification.

The SDK wraps the raw API with the plumbing you’d otherwise write yourself: response caching, ETag revalidation, offline receipt verification, and a tag gate that blocks trackers until consent actually allows them.

npm i @croombit/sdk

Client

import { CroombitClient } from '@croombit/sdk';

const tc = new CroombitClient({
  baseUrl: 'https://api.croombit.com',
  apiKey: 'pk_live_…',      // sk_live_… on a server
  cacheTtlMs: 60_000,       // optional
});

Methods

  • recordConsent(params, { idempotencyKey }) · recordConsentBatch(records) · recordPreferences(params)
  • getConsentState(subject, { purpose?, fresh? }) · getPreferences(subject) — ETag-cached
  • getPurposes({ locale? }) · getPurpose(key, { locale? }) · getPreferenceTemplate() · getPolicy({ country? })
  • getTcString(subject) · getConsentMode(subject) · applyConsentMode(subject, gtag) · getGppString(subject)
  • getReceipt(id) · verifyReceipt(receipt) — Ed25519 offline via Web Crypto
  • createPortalToken(subject) · createSubject · addIdentifier · mergeSubjects · createDataRequest — require sk_
  • getConsentHistory(subject, { purpose? }) · getPreferenceHistory(subject, { field? }) — the append-only history, newest first; require sk_ (see Guide: showing a user their own history)
  • getWebhookEvents() — the webhook event catalog and delivery contract (GET /v1/webhook-events)

recordConsent and recordConsentBatch accept source: 'API' | 'IMPORT' | 'MIGRATION' (default API). IMPORT and MIGRATION mean you assert the record, not the subject, and need an sk_ key — see Who acted: source.

Server helpers

The @croombit/sdk/server entry is for your backend only (Web Crypto, no dependencies; Node 18+, Deno, Bun, edge runtimes):

  • signIdentityToken(…) — vouch for a logged-in user so a pk_ key can reach them (guide)
  • constructWebhookEvent({ header, rawBody, secret }) — verify a webhook signature and return the typed event; throws WebhookSignatureError
  • verifyWebhookSignature({ header, rawBody, secret, toleranceSeconds? }) — the same check as a boolean
  • WEBHOOK_EVENTS · WebhookEventType · WebhookEvent — the event names and types

A complete receiver is in Webhooks: payloads & signature.

Tag gate

// load your scripts only once the subject has granted one of these purposes
await tc.gate('email:user@example.com', ['analytics'], () => loadAnalytics());

// after your banner writes new consent:
tc.notifyConsentChanged();

Reading preferences

getPreferences returns the current preference-center state for a subject — channels, topics and typed fields — derived from POST /v1/preferences writes.

const prefs = await tc.getPreferences('email:user@example.com');
// prefs.channels['marketing'].topics['newsletter'].state === 'GRANTED'

Double opt-in (email preferences)

For email marketing, many regulations require confirmed opt-in. Use createPreferenceConfirmationToken from your server (it needs an sk_ key — the token is the whole capability, so it must never reach a browser) to trigger the confirmation email; the recipient clicks a link that calls POST /v1/preferences/confirm.

// 1. Write a pending preference and request the confirmation email (server, sk_)
const { token, confirmUrl } = await tc.createPreferenceConfirmationToken({
  subject: 'email:user@example.com',
  values: [{ field: 'newsletter', value: true }],
  channel: 'email',
  redirectUrl: 'https://acme.com/subscription/confirmed', // must be on one of your site's domains
});
// Your email service sends confirmUrl — or pass `to: 'user@example.com'` (the subject's own
// address) and Croombit sends it for you.

// 2. No further action needed — the confirmation endpoint writes GRANTED
//    and the webhook preference.confirmed fires.
The pending preference is NOT counted as consent until confirmed. getPreferences returns PENDING until the link is clicked.