Creating a Custom Consent UI

We provide an open source reference UI package that can be extended however you see fit. This package provides a strong foundation with full regime-specific UI integration, compatibility with our auto-prompt functionality, and translations for 54 languages.

https://github.com/transcend-io/consent-manager-ui

See this doc to learn more about customizing the stylesheet (CSS) for our out-of-the-box UIs rather than building an entirely custom UI.

To prevent our default UI module from loading, add a data-ui="off" attribute to your airgap.js script tag.

If your own UI is available as a discrete external JavaScript file, you can optionally replace our UI module and airgap.js will asynchronously auto-load your module instead by specifying a URL in the data-ui script attribute.

If your UI setup code runs before airgap.js core is initialized, you will need to use airgap.ready() as demonstrated below:

// Stub airgap.js ready queue
if (!self?.airgap?.ready) {
  self.airgap = {
    readyQueue: [],
    ready(callback) {
      this.readyQueue.push(callback);
    },
    ...self?.airgap,
  };
}

// Wait for airgap.js core to load
self.airgap.ready((airgap) => {
  // Init your UI DOM here
});

Every airgap.js API that can mutate consent state requires a genuine user gesture (event.isTrusted == true) which can be either any UIEvent (e.g. click) or a form submit event.

Script load events that fired prior to airgap.js initialization can also be used as valid consent authorization.

<script
  data-cfasync="false"
  src="https://transcend-cdn.com/cm/443312ef-12f9-494d-85f5-969894260cc7/airgap.js"
  onload="setAirgapAuth(event);"
></script>

You should pass the load event value to your own trusted code for safekeeping in setAirgapAuth(event). That event can later be used when authorization is required, like for airgap.getConsent() (see below)

airgap.setConsent(getAirgapAuth(), consent);

airgap.getConsent() returns an TrackingConsentDetails descriptor. This descriptor has a purposes field which returns an object keyed by all consentable tracking purpose types. The descriptor also has an ISO 8601 timestamp accessible via the timestamp field.

getConsent() Example

await airgap.sync();
const consent = airgap.getConsent().purposes;
console.log(JSON.stringify(consent, null, 2));

airgap.getConsent().purposes output:

{
  "Functional": false,
  "Analytics": false,
  "Advertising": false
}

airgap.setConsent() sets user consent for individual tracking purposes. A trusted interaction Event (or the script load event for the airgap.js script) is required by this API.

Example

saveConsentButton.addEventListener('click', (interaction) => {
  airgap.setConsent(interaction, serializeConsent());
});

ℹ️ The first argument to airgap.setConsent must be a native click or submit Event. If you're using React, your event may be a SyntheticEvent. In this case, you will need to pass interaction.nativeEvent.

await airgap.sync();

const hasPrivacyRights = airgap.getRegimePurposes().size !== 0;

// Is user fully opted-in to core unessential tracking purposes:
// Functional, Analytics, and Advertising
const isOptedIn = airgap.isOptedIn();

// a similar utility is available for detecting full opt-out
// of these purposes:
// const isOptedOut = airgap.isOptedOut();

const consentForm = document.getElementById('...');
const consentCheckbox = document.getElementById('...');
consentCheckbox.checked = isOptedIn;

if (hasPrivacyRights) {
  consentCheckbox.addEventListener('change', (interaction) => {
    if (interaction.target.checked) {
      // Consent to all user-configurable tracking purposes
      airgap.optIn({ interaction });
    } else {
      // Opt-out of all user-configurable tracking purposes
      airgap.optOut({ interaction });
    }
  });
} else {
  consentForm.style.display = 'none';
  consentCheckbox.disabled = true;
}

Consent can be set on a per-purpose level using airgap.getConsent()airgap.setConsent(), and airgap.getPurposesTypes().

airgap.getPurposesTypes() returns airgap's current TrackingPurposesTypes config. This config data can be used in conjunction with airgap.getConsent() to inform the content of a custom consent UI.

const purposes = airgap.getPurposesTypes();
console.log(JSON.stringify(purposes, null, 2));

airgap.getPurposesTypes() example output:

{
  "Functional": {
    "name": "Functionality",
    "description": "Personalization, autofilled forms, etc.",
    "defaultConsent": false,
    "showInConsentManager": true,
    "configurable": true,
    "essential": false
  },
  "Analytics": {
    "name": "Analytics + Performance",
    "description": "Help us learn how our site is used and how it performs.",
    "defaultConsent": false,
    "showInConsentManager": true,
    "configurable": true,
    "essential": false
  },
  "Advertising": {
    "name": "Targeting / Advertising",
    "description": "Helps us and others serve ads relevant to you.",
    "defaultConsent": false,
    "showInConsentManager": true,
    "configurable": true,
    "essential": false
  },
  "Essential": {
    "name": "Essential",
    "description": "",
    "defaultConsent": true,
    "showInConsentManager": false,
    "configurable": false,
    "essential": true
  },
  "Unknown": {
    "name": "Unknown",
    "description": "",
    "defaultConsent": false,
    "showInConsentManager": false,
    "configurable": false,
    "essential": false
  }
}