Privacy and Security for Consent

Our consent manager is carefully designed to protect its own internal state and regulation capabilities from other potentially malicious scripts running in the same environment. We employ the following techniques to ensure the security of our consent manager:

We use an extensive runtime reference caching & utility framework as the standard library through which all of our security-critical code is built. This library is completely resistant to all prototype pollution attacks, and dynamically adjusts for implementation differences between browsers to always provide the most secure level of abstraction available.

We do not include any third-party dependencies in our airgap.js or Transcend XDI builds as nothing else meets our strict security standards. Our JavaScript bundler (esbuild) injects some utilities to assist with transpilation.

We require a genuine user-initiated 'click' or 'submit' event or a trusted Transcend XDI consent sync to change consent after initialization. A 'load' event that fired before/as airgap.js initialized may also be used as authorization, and is exclusively required for more dangerous APIs such as airgap.toggle(auth: AirgapAuth, protectionState?: boolean) that can toggle protections.

While our request and cookie watcher APIs requires no authorization, our request and cookie override APIs require a 'load' event that fired before/as airgap.js initialized as authorization.

airgap.js 9.7 and later supports a strict auth mode where additional authorization is required to change consent or access privileged APIs. This mode can be enabled with data-require-auth="strict".

Strict authorization mode requires a reference to a 'load' event that fired before/as airgap.js initialized to access privileged APIs that affect regulation capabilities, such as request override and airgap.toggle() APIs. Consent mutation APIs additionally accept authorization composed of both a genuine user interaction event and the unique consent change auth key transferred to the UI module through the transcend.setAuth() API. Our currently-shipping UI module is not yet compatible with this mode, so we don't recommend using it yet.

This example shows how to use the transcend.setAuth() API to support strict authorization mode in a custom UI module:

// Custom consent management UI module

if (!self.airgap?.ready) {
  self.airgap = {
    readyQueue: [],
    ready(callback) {
      this.readyQueue.push(callback);
    },
    ...self.airgap,
  };
}
self.airgap.ready(() => {
  let consentChangeAuthKey;

  // Initialize API
  const transcend = (self.transcend = {
    readyQueue: [],
    ...self.transcend,
    setAuth(key) {
      consentChangeAuthKey = key;
    },
    ready(callback) {
      callback(transcend);
    },
  });

  // Process ready queue
  for (const callback of transcend.readyQueue) {
    try {
      callback(transcend);
    } catch () {}
  }
  transcend.readyQueue.length = 0;
  delete transcend.readyQueue;

  // Call your custom UI creation function
  const ui = initUI();

  // Add event listeners
  const actions = ['optOut', 'optIn'];
  actions.forEach((action) => {
    ui.actionButtons[action].addEventListener('click', (interaction) => {
      airgap[action]({ key: consentChangeAuthKey, interaction });
    });
  });

  // Append UI to document
  (document.documentElement || document).appendChild(ui.root);
});

This mode can restrict the ability of third-party components that load after airgap.js to clickjack consent write access.

Read before activating tamper resistance

Note that an interaction between Chrome 117, Transcend Consent's tamper resistance mode, and versions of regenerator-runtime (a common JavaScript library) older than v0.13.8 can cause errors and could negatively impact your website. To resolve these errors please update airgap.js to version 8.11.11 or higher to automatically disable tamper resistance mode. If you're using an earlier version of airgap.js and are unable to update, you can also manually disable tamper resistance by setting the the data-tamper-resist="off" attribute on your airgap.js script.

Tamper resistance is an optional advanced mode that helps airgap.js avoid interference from potentially malicious adtech installed on a website.

When this mode is enabled, we employ active tamper resistance interventions that prevent third-party code from redefining some built-in JavaScript iterators and methods which are insecurely used by the utilities generated by our JavaScript bundler. This protection augments our use of a reference cache & utility framework to secure against prototype pollution attacks.

Note that tamper resistance mode is not required for Transcend Consent's regulation functionality and is an optional additional protection.

Tamper resistance mode was formerly enabled by default. Beginning in airgap.js version 8.11.11 it is now disabled by default. If you're running airgap.js 8.11.11 or higher and would like to enable tamper resistance, you can set the data-tamper-resist="on" attribute on your airgap.js script.

The following are the storage areas used by each Transcend Consent Management component and their purpose:

  • localStorage.tcmConsent: A JSON object storing the user's consent state. The format of the JSON object is documented here.
  • localStorage.tcmMPConsent: A JSON object keyed by site-defined partitions. Each entry represents an individual entry in the same format as localStorage.tcmConsent. This is used to segregate consent for sites with multiple discrete same-origin sub-sites.
  • localStorage.tcmQuarantine: A stringified JSON object storing the requests and cookies that are held in "quarantine" before the user consents to having their data be used for various tracking purposes. You can read more about event quarantine capabilities here. Transcend Consent Management can be configured to not store this information by following the instructions here.
  • localStorage.tcmu: Unreported count of "page views" that we track for reporting purposes and for triggering pageview-based auto-consent-prompting. This data is sent to our backend and processed as an aggregate count.
  • localStorage.tcmr: Reported count of "page views" that we track for reporting purposes and for triggering pageview-based auto-consent-prompting.
  • sessionStorage.tcms: Used to track cumulative sessions for reporting purposes. This data is used to generate a session count that is sent to our backend.
  • Future: IndexedDB tcm database: This database will be used to store quarantined events.
  • localStorage.tcm: A JSON object storing user consent, consent metadata, and quarantine data for multiple third-party sync groups. This value was stored at localStorage.tcm3PConsent prior to airgap.js 8.38.0.

Information that may be stored if you're using Transcend's Preference Store to store and persist consent for known users. Learn more.

FieldDescription
Encrypted IdentifierEncrypted identifier provided by the Transcend Customer for the end user associated with the consent record.
PartitionThe bundle ID of the Transcend Consent Management instance that collected consent. For customers with multiple partitioned airgap bundles, this will be the partition ID.
PurposesMap of consent purposes associated with the record
TimestampWhen consent record was created in ISO format (e.g. "2023-05-11T19:32:31.707Z")
airgap.js Version (Optional)airgap.js version in use at time of collection
Metadata (Optional)Storage of additional metadata - can be configured by the customer as needed
Metadata Timestamp (Optional)Timestamp for last optional metadata update