VoidhashDocs
DevelopersHelp centerGuidesAPI reference
Dashboard
Get started
Introduction
Quickstart
How Voidhash works
Glossary
Versions and releases
Concepts
Teams, projects and environments
API keys
Products and perks
Offers
Subscription lifecycle
People and identity
Events
Features
Paywalls in your app
Feature flags and A/B tests
Paywall components
Push notifications
Ad attribution in your app
Client SDKs
React Native
Swift
Kotlin
Web
Your backend
Node.js
PHP
Go
Rust
Other languages
Payment sources
Forward store notifications
Developer tools
CLI
MCP server
Query analytics with VoidQL
Web SDK
Web quickstart
Script tag
Identify users
Evaluate feature flags
Track
Track events
Page views and attribution
Privacy
Privacy and consent
Browser storage
Connect a consent tool
Keep data out of analytics
Revenue and attribution
Sell on the web
Stripe revenue
Web-to-app handoff
Delivery
First-party proxy
Tracking domain
Reference
Web SDK reference
Errors
Troubleshooting

Connect a consent tool

Let Cookiebot, OneTrust or another consent tool decide when the web SDK records analytics.

A consent tool such as Cookiebot or OneTrust keeps the answer itself and often loads after your script. Make it the only source of consent with analyticsConsentSource: "app":

import { createVoidhashClient } from "@voidhash/web";

export const voidhash = createVoidhashClient({
  analyticsConsentSource: "app",
  publishableKey: "vh_pk_...",
  storeBeforeConsent: false,
});
void voidhash.initialize();

storeBeforeConsent: false keeps the SDK's state off the device until consent; see Ask for consent first.

Pass every answer

Pass every answer the tool reports to setAnalyticsConsent(): the stored answer on each page load, and every change. With "app", every page starts from the analyticsConsent option (pending by default), whatever an earlier visit stored. pending records nothing and discards nothing: events earlier pages queued wait for the answer. If you know the answer when creating the client, pass it as analyticsConsent.

Cookiebot's statistics category covers analytics:

declare global {
  interface Window {
    Cookiebot?: { consent: { statistics: boolean }; hasResponse: boolean };
  }
}

function applyCookiebotConsent() {
  const cookiebot = window.Cookiebot;
  if (!cookiebot) return;
  // Before the visitor answers, `statistics` is false too: that is `pending`, not `denied`.
  void voidhash.setAnalyticsConsent(
    cookiebot.consent.statistics ? "granted" : cookiebot.hasResponse ? "denied" : "pending",
  );
}

for (const event of ["CookiebotOnConsentReady", "CookiebotOnAccept", "CookiebotOnDecline"]) {
  window.addEventListener(event, applyCookiebotConsent);
}
// Cookiebot may have loaded the answer before this code ran.
applyCookiebotConsent();

OneTrust usually puts analytics in its Performance category, C0002; check the ID under Categorization → Categories in OneTrust.

declare global {
  interface Window {
    OneTrust?: { IsAlertBoxClosed: () => boolean };
    OnetrustActiveGroups?: string;
  }
}

const ANALYTICS_CATEGORY = "C0002";

function applyOneTrustConsent(activeGroups: string | ReadonlyArray<string>) {
  // Until the visitor answers, or after their answer expired, the banner is open: `pending`.
  void voidhash.setAnalyticsConsent(
    activeGroups.includes(ANALYTICS_CATEGORY)
      ? "granted"
      : window.OneTrust?.IsAlertBoxClosed()
        ? "denied"
        : "pending",
  );
}

window.addEventListener("OneTrustGroupsUpdated", (event) => {
  if (event instanceof CustomEvent) applyOneTrustConsent(event.detail);
});
// OneTrust may have loaded before this code ran.
if (window.OnetrustActiveGroups) applyOneTrustConsent(window.OnetrustActiveGroups);

Next steps

  • Privacy and consent
  • Web SDK reference

Something wrong or missing on this page? Tell us by email or on Discord.

PreviousBrowser storageNextKeep data out of analytics

On this page

Pass every answerNext steps