airgap.js API Reference

airgap.js tags requests with various tracking purposes, coming from your data flows config, any applicable overrides, and regulatedPaths & regulatedScripts filters.

First, airgap.js resolves pending request URLs by applying all applicable request overrides. Overrides can change URLs, add/remove tracking purposes, and force-allow/deny requests, with all of these features available to customer-defined logic. If the request is not force-allowed/denied by an override, the finalized URLs are then inspected against regulated resource matchers (that can tag purposes based on paths).

If the request is a script, airgap.js first compares the request URL with every regulatedScript filter. If loadOptions.regulateAllScripts === "off", all scripts that don't match any regulatedScripts filters are tagged with Essential purposes.

Finally, airgap.js compares the request URL with every regulatedPaths filter and tags the request with purposes from any matching filters. Then airgap.js searches the purpose map for the request's domain. If there is a match, those purposes are tagged on the request.

If the resulting tracking purposes include essential purposes (e.g. ['Essential', 'Analytics'], ['Essential', 'Unknown'], or ['Essential']), then the essential purposes override all other purposes. Anything tagged as essential will be allowed through by airgap.js.

See How do I set user consent from my website UI?

See Restoring consent to logged-in users from your backend.

Post-airgap.ready(), self.airgap becomes an EventTarget that can emit all the following events:

This is emitted whenever consent is changed through sync or through user interaction with a consent interface.

Example usage:

airgap.addEventListener(
  'consent-change',
  ({ detail: { consent, oldConsent, changes } }) => {
    console.log(`consent-change event:`, { consent, oldConsent, changes });
  }
);

Unlike consent-change, this is only emitted once per page load. This event represents either new consent resolution or previously-stored consent being loaded. This event can additionally indicate if a user's privacy preference signals affected consent resolution.

Example usage:

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

self.airgap.ready((airgap) => {
  airgap.addEventListener(
    'consent-resolution',
    ({ detail: { consent, oldConsent, changes, signals } }) => {
      console.log(`consent-resolution event:`, {
        consent,
        oldConsent,
        changes,
        signals,
      });
    }
  );
});

This is emitted whenever the Transcend Consent Management UI changes state. The list of possible ViewStates is published here and has TypeScript types available here. Please note that, unlike the other events, you must register the listener for view-state-change with self.transcend and not self.airgap.

Usage:

transcend.addEventListener(
  'view-state-change',
  ({ detail: { viewState, previousViewState } }) => {
    console.log(`consent view state changed:`, {
      viewState,
      previousViewState,
      timestamp: new Date().toISOString(),
    });
  }
);

A more complete example:

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

// Wait for consent manager UI to load
self.transcend.ready((transcend) => {
  // Add the event listener
  self.transcend.addEventListener(
    'view-state-change',
    ({ detail: { viewState, previousViewState } }) => {
      console.log(`consent view state changed:`, {
        viewState,
        previousViewState,
        timestamp: new Date().toISOString(),
      });
    }
  );
});

This is emitted whenever local or remote sync completes. These are the same format as consent-change events.

All load options can be configured by specifying data-* attributes on your airgap.js script tag or by defining the corresponding dataset.* attribute as airgap.loadOptions.* prior to init. For example, data-disable-when-consented="on" would map to airgap.loadOptions.disableWhenConsented = 'on'.

The userscript simulation utility also allows load option configuration by manually setting localStorage.tcmLoadOptions to a JSON object string:

// set load options for consent manager simulation userscript:
localStorage.tcmLoadOptions = JSON.stringify({
  log: '*',
  prompt: 'auto',
  /* etc. */
});

Requests that are not associated with any purposes from the purpose map can be either blocked, always allowed, or allowed with full consent. This feature defaults to block when CSP is enabled and allow whenever CSP is disabled. This can be configured by setting data-unknown-request-policy="…" on your airgap.js script tag.

Possible values:

  • block (default with CSP enabled) — Always block unknown requests
  • allow (default with CSP disabled) — Always allow unknown requests
  • require-full-consent — Allow unknown requests if the user has consented to all first order (i.e. Functional, Advertising, Analytics) tracking purposes

Similar to unknown request policy, cookies that are not associated with any purposes from the cookie purpose mount can be blocked, always allowed, or allowed before consent. The default policy is allow. This can be configured by setting data-unknown-cookie-policy="…" on your airgap.js script tag.

Request regulation prevents network APIs and network request-generating DOM nodes from making unauthorized requests using a combination of mutation observers and prototype patchers. Request regulation can be disabled by setting data-protect="off" on your airgap.js script tag.

Cookie regulation uses cookie API patchers to prevent unauthorized cookies from being set using JS APIs. Cookie regulation can be disabled by setting data-regulate-cookies="off" on your airgap.js script tag.

CSP protection uses a dynamically-generated Content-Security-Policy meta tag to prevent unauthorized network access. This can be configured by setting data-csp="…" on your airgap.js script tag.

CSP protection is off by default unless the unknown request policy is set to “Block”, in which case CSP protection is on and in lax mode by default.

  • No CSP: data-csp="off"
  • [Lax mode] Allow all hosts categorized in your data flows and their subdomains: data-csp="allow-known-hosts allow-subdomains"
  • Allow consented hosts and their subdomains: data-csp="allow-subdomains"
  • Allow consented hosts: data-csp="strict"

airgap.js can be configured to automatically disable airgap.js protection (including DOM patchers and Content Security Policy) when fully consented by setting data-disable-when-consented="on" on your airgap.js script tag. When this mode is enabled, airgap.js will automatically enable protections as needed whenever tracking consent changes.

Sometimes there will not be any applicable privacy legal regimes detected for a user. Setting data-default-regime="CPRA" (or "GDPR", etc.) makes airgap.js behave as if users without any applicable privacy legal regimes were detected with the specified default privacy legal regime.

In addition to changing the default for users with no applicable consent experience, you can directly set the privacy regime by adding a data-regime="CPRA" (or "GDPR", etc.) attribute on the Airgap.js script tag. Using this setting is a good option for those that use a native first-party tool to aid in regime detection.

Multiple regimes can be specified by separating them with spaces.

When consent changes, the Content Security Policy can only be updated with a page refresh. By default, airgap.js will refresh the page when consent changes as needed depending on CSP scope. To disable this, set data-auto-reload="off" on your airgap.js script tag. Automatic refresh is not necessary when CSP is configured to allow all known hosts (data-csp="allow-known-hosts").

By default, airgap.js blocks scripts that do not map to consented tracking purposes and postpones their execution for later consent. To disable this feature and allow all scripts to run by default, set data-regulate-all-scripts="off" on your airgap.js script tag.

In order to auto-display the consent prompt UI, set data-prompt=auto. The prompt can also be optionally auto-displayed with a delay based on number of pageviews with data-prompt=[# of pageviews].

For example, data-prompt=3 will cause airgap.js to auto-display the consent prompt UI during a user's third pageview on your site. Consent prompt can be prevented by using data-prompt=0.

Quarantined events can be automatically discarded after a certain expiration time limit by setting data-auto-expire=[# of minutes]. For example, setting auto-expire=1440 will cause quarantined events to automatically expire after 24 hours.

Extended Sync allows for event quarantine and consent metadata to be synchronized in addition to consent. In order to use Extended Sync, you must self-host your own XDI host endpoint.

Extended Sync can be disabled by adding data-extended-sync="off" to your xdi.js script tag.

Transcend Consent's multiple JavaScript modules and synchronization endpoint can be self-hosted on your own infrastructure to help comply with internal security requirements.

You can find more information on the benefits of self-hosting Transcend Consent, and how to do so in this documentation section.

If you want to use an external stylesheet rather than customize the default stylesheet, you can replace the default via data-css=”/path/to/your/stylesheet.css” attribute on the script tag. As an option, the default stylesheet is available as part of Transcend’s open source reference UI to clone, modify and host as well.

You can customize the link to your privacy policy by setting the data-privacy-policy attribute to your policy URL. This data attribute will override the value of the privacy policy link that is set in the Admin Dashboard.

The CompleteOptionsInverted view state also uses the data-secondary-policy data attribute to display a secondary policy link.

You can filter down the list of languages supported in consent prompts by using the data-languages load option. Ex. data-languages="en,es-ES,fr-FR" The list of support languages can be found here.

You can also set data-locale on the script tag to set the default locale. Ex. data-locale="fr-FR" This value can also be set using transcend.setActiveLocale('fr-FR').

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.

More information on how to create your own UI can be found in this guide.

Setting data-monitoring="export" on your airgap script will enable the use of airgap.export().sentRequests and airgap.export().setCookies to visualize requests and cookies that have been allowed by airgap.

More info on debugging APIs can be found here.

By default, airgap.js will try to load purpose maps asynchronously in the background unless a purpose map is embedded by pre-defining airgap.purposeMap prior to airgap.js init. Transcend Consent Management always pre-defines this value.

airgap.js may run into scenarios where it must make a synchronous XMLHttpRequest in order to request purpose maps in time to regulate a synchronous network request generating event. If you wish to require asynchronous loading, set data-sync-xhr="off" on your airgap.js script tag. This can result in requests being blocked due to purpose maps not being loaded in time.

When request monitoring is enabled, airgap.js will monitor all emitted requests for more in-depth metric collection. These requests are exposed for inspection via airgap.watch().

airgap.js can cache a buffer of all sent requests, accessible via airgap.export().sentRequests. This can be enabled by setting data-request-monitoring="export" on your airgap.js script tag.

By default, airgap.js will display a persistent floating widget after the consent banner is dismissed to provide users an easy way to get back to the banner. This floating widget can be disabled by setting data-dismissed-view-state="Closed" on your airgap.js script tag.

airgap.js employs active tamper resistance mitigations to secure its own internal state from manipulation by potentially malicious scripts. This feature can be disabled by setting data-tamper-resist="off" on your airgap.js script tag.

Read more: Security: Tamper resistance

airgap.js can be used in report-only mode to collect network analytics on a page to feed back into request categorization and purpose map generation software. Report-only mode automatically enables request monitoring and attempts to allow all requests through. This mode can be enabled by setting data-report-only="on" on your airgap.js script tag. This mode is best paired with the airgap.export() API method.

airgap.js can log encountered hosts and errors to an external endpoint in order to help sites build purpose maps with better real-world coverage. Reported telemetry data can be reduced to usage data essential to billing by setting data-telemetry="usage" on your airgap.js script tag. The telemetry sync period can be configured via data-telemetry-sync-period="[seconds]" and defaults to 5 minutes (300 seconds). The initial sync period can be configured separately via data-initial-telemetry-sync-period="[seconds]" and defaults to 30 seconds.

Example telemetry payload:

{
  "site": "example.com",
  "hosts": "example.com 5 \n transcend-cdn.com \n example.org 2 \n wss:uses-websockets.example 4"
}

Host encounter tally format (.hosts):

// entry = [optional protocol scheme:]host[ optional request count=1]
// entries = entry[] separated by newlines with optional extra spaces

Transcend Consent Management can send low-priority network requests to emit telemetry without impacting site performance. The default behavior is to use low-priority network requests except when a pending telemetry payload contains billing usage details. This can be configured by setting the data-prioritize-telemetry="…" attribute on the airgap.js script element.

Supported values:

  • on — Always use high-priority network requests for telemetry.
  • usage — Only use high-priority network requests for telemetry payloads containing billing usage details (default)
  • off — Always use low-priority network requests for telemetry. Users with adblockers will block all telemetry.

A 'bounce' is a pagehide event during the first pageview in a session, except when the user has recently interacted with the page in the last 600ms.

The bounce counter debounce threshold can be configured by specifying data-bd-interaction-threshold="[time in ms]" on the airgap.js script element.

airgap.js can sync consent & quarantine data cross-domain without external requests over the Transcend XDI protocol. Sync can be disabled by setting data-sync="off" on your airgap.js script tag. The default endpoint used by airgap.js is uniquely generated for your consent manager bundle. The sync endpoint can be configured by setting data-sync-endpoint="[URL]" on your airgap.js script tag.

airgap.js can be configured to only sync certain types of data with sync: "[type1] [type2] [etc]" (e.g. sync: "consent quarantine") in your loadOptions.

To enable sync of all data, set sync: "*" or sync: "on". To disable sync entirely, set sync: "off".

The default setting is to sync all data.

airgap.js can be configured to conditionally emit console logs that match a list of allowed log tags. You can allow specific logs tags to be emitted by adding data-log="[tag1] [tag2] [etc]" (e.g. data-log="error warn") on your airgap.js script tag. To enable all log tags, set data-log="*" on your script tag. To completely disable logging, set data-log="off". The default value is "error warn".

airgap.js can be configured to only replay certain types of events with data-replay="[type1] [type2] [etc]" (e.g. data-replay="requests mutations cookies") on your airgap.js script tag. To enable replay of all events, set data-replay="*" or data-replay="on" on your script tag. To disable replay entirely, set data-replay="off". The default setting is to replay all events.

airgap.js can be completely disabled by setting data-disabled="on" on your airgap.js script tag. This setting prevents all of airgap.js from initializing.

By default, airgap.js regulates script requests like any other request. In order to block certain scripts from loading based on their URL using a declarative API, define airgap.regulatedScripts: RegulatedPathConfig[] before loading airgap.js. All script URLs will be screened against this array if defined, with strings being matched with startsWith and regular expressions being tested against the entire URL.

Regulated scripts are checked against the purpose map and regulated like any other resource with the replay quarantine.

interface RegulatedPathConfig {
  /**
   * Regulated path matcher.
   *
   * Potential formats:
   * - Relative path (same-site): /path/to/resource
   * - Relative path (any-site): ///path/to/resource
   * - Protocol-less path: //site//path/to/resource
   * - Absolute path: https://site/path/to/resource
   * - Query parameter: ?param=value
   * - RegExp
   *
   * Syntax examples:
   * Match example.com/collect-analytics
   * matcher: '//example.com/collect-analytics'
   *
   * Match [any site]/collect-analytics
   * matcher: '///collect-analytics'
   */
  matcher: string | RegExp;
  /** Purposes to tag onto matching requests */
  purposes: string[];
  /** Parse string with RegExp() constructor */
  regex?: boolean;
}

In order to block certain locations from loading based on their URL and not just their hostname, define airgap.regulatedPaths: RegulatedPathConfig[] before loading airgap.js. All URLs will be screened against this array if defined, with strings being matched with startsWith and regular expressions being tested against the entire URL.

Regulated scripts are checked against the purpose map and regulated like any other resource, with a replay quarantine.

In order to prevent cookies from being included in certain requests, define airgap.omitCredentials: RegulatedPathConfig[] before loading airgap.js. RegulatedPathConfig.purposes constraints are optional for omitCredentials matchers. If RegulatedPathConfig.purposes is not defined, matcher is always applied for matching paths.

When a request matches an omitCredentials RegulatedPathConfig, airgap.js will try to modify the request to prevent cookies from being included.

Returns a promise which resolves to true if the URL is allowed, or false otherwise. Set resolveOverrides to false to disable request overrides.

Returns a promise which resolves to true if the PendingRequest is allowed, or false if denied. Set resolveOverrides to false to disable request overrides.

Returns a promise which resolves to true if the cookie is allowed, or false otherwise. Set resolveOverrides to false to disable cookie overrides.

Returns a promise which resolves to the set of tracking purposes associated with the URLs provided. Set resolveOverrides to false to disable request overrides.

Returns a promise which resolves to the set of tracking purposes associated with the provided request. Set resolveOverrides to false to disable request overrides.

Returns a promise which resolves to the set of tracking purposes associated with the provided cookie mutation. Set resolveOverrides to false to disable cookie overrides.

Returns a set of all privacy legal regimes that are detected as applicable to the user. This is used internally to inform our 'auto' default consent logic and help us choose the right consent UI paradigm in our UI module.

Example

Detecting GDPR and CCPA/CPRA-protected users:

const regimes = airgap.getRegimes();
const EU_GDPR = regimes.has('GDPR');
const California_CPRA = regimes.has('CPRA');
if (EU_GDPR && California_CPRA) {
  // handle regulatory nuance for Europeans vacationing in California
}

PrivacyRegime definition

/** Potentially applicable data privacy legal regimes */
type PrivacyRegime =
  /** California Privacy Rights Act (and CCPA: California Consumer Privacy Act) */
  | 'CPRA'
  /** EU General Data Protection Regulation */
  | 'GDPR'
  /** Brazil Lei Geral de Proteção de Dados (General Personal Data Protection Law) */
  | 'LGPD'
  /** Virginia Consumer Data Protection Act */
  | 'CDPA'
  /** Colorado Privacy Act */
  | 'CPA';

Protects a node using DOM protection mechanisms. Defaults to document. Returns an object with a removal function to disable DOM protection.

Protects the document using a dynamically-generated Content-Security-Policy based on tracking consent preferences and the currently loaded purpose map (if any). CSP policy directives can be manually specified to customize CSP initialization. For example, airgap.activateCSP(['allow-subdomains', 'allow-known-hosts']) will initialize a CSP that allows all known hosts on the purpose map and their subdomains.

Registers an airgap.js ready queue listener. This is only necessary to be called when asynchronously loading airgap.js.

Regulates all scripts that are added to the document after based on their purposes. This method is only necessary if you turn off script regulation with data-regulate-all-scripts="off".

Returns whether all scripts are currently regulated according to tracking purposes. If this returns false, all scripts (except for those matching regulatedScripts) are allowed.

Enqueues a cross-domain data sync across all Transcend Consent Management allowed domains and resolves when sync is complete.

Returns the user's current tracking consent details.

Returns whether the user's tracking consent was able to be updated without a refresh. If CSP is active, a refresh is required to update enforcement of the user's tracking consent.

Returns whether the user's tracking consent was able to be updated without a refresh. This function consents the user to all tracking purposes.

Returns whether the user's tracking consent was able to be updated without a refresh. This function revokes consent for all tracking purposes.

Returns whether the user is consented to all tracking purposes that are configurable: true & not showInConsentManager: false. You can query tracking purpose details from airgap.getPurposeTypes()

Returns whether the user has opted out of all tracking purposes that are configurable: true & not showInConsentManager: false. You can query tracking purpose details from airgap.getPurposeTypes()

Registers request overrides to conditionally override pending request URLs via custom logic (through function-based overrides) or using airgap's RegExp-based match-and-replace system. Returns a cleanup helper with a remove() method.

Pre-init API example:

self.airgap = {
  overrides: [
    // This override executor is run on every request
    {
      override(request) {
        request.URLs.forEach((url, i) => {
          if (customCondition) {
            request.urls[i] = '//foo.bar';
          }
        });
      },
    },
    // This override is gated by a regex
    {
      // Upgrade all .png requests to .webm
      matcher: /^(.*)\.png(\?.*)?$/,
      override: '$1.webm$2',
    },
    // This override is gated by a regex & lack of consent
    {
      // Reduce amount of tracking
      unconsented: ['Advertising'],
      matcher: /^([\w-]+:\/*adsite\.example)\/extra-tracking/,
      override: '$1/less-tracking',
    },
    // This override is gated by a regex and uses a custom executor
    {
      // Upgrade .png requests to .webm for certain domains
      matcher: /^(.*)\\.png(\\?.*)?$/,
      override(request, matcher) {
        request.URLs.forEach(({ hostname, pathname }, i) => {
          if (webmDomains.includes(hostname) && pathname.endsWith('.webm')) {
            request.urls[i] = url.replace(matcher, '$1.webm$2');
          }
        });
      },
    },
  ],
  ...self.airgap,
};

Runtime (post-init) API example:

someButton.addEventListener(
  'click',
  (interaction) => {
    const { remove } = airgap.override(
      { interaction },
      {
        matcher: /^([\\w-]+:\\\/*ad-site.example)\\\/extra-tracking/,
        override: '$1/less-tracking',
      }
    );

    // '<http://ad-site.example/extra-tracking>' is now overridden to
    // '<http://ad-site.example/less-tracking>'

    // remove() removes overrides registered by this airgap.override() call
  },
  { once: true }
);

Requests can be marked to persist for cross-session replay by setting request.persist = true in a request override.

// prior to loading airgap.js
const noPersistHosts = new Set(['fresnel.vimeocdn.com' /*  ... */]);
self.airgap = {
  overrides: [
    {
      override(event) {
        // don't persist requests to anything on the noPersistHostList
        const shouldPersist = !event.URLs.some(({ hostname }) =>
          noPersistHosts.has(hostname)
        );
        event.persist = shouldPersist;
      },
    },
    {
      matcher: /^[\w-]+:\/.*fresnel\.vimeocdn\.com\//,
      // don't persist requests to fresnel.vimeocdn.com (using a regexp matcher)
      override(event) {
        event.persist = false;
      },
    },
    {
      override(event) {
        // persist all script requests cross-session
        if (event.type === 'DOM:script') {
          event.persist = true;
        }
      },
    },
  ],
};

Register cookie overrides to conditionally override pending cookie data via custom logic through function-based overrides. Returns a cleanup helper with a remove() method.

Pre-init API example:

self.airgap = {
  cookieOverrides: [
    // This override executor is run on every cookie mutation
    (cookie) => {
      if (customCondition) {
        // e.g. restrict cookie to certain values, etc.
        cookie.value = customCookieValue;
      }
    },
  ],
  ...self.airgap,
};

Runtime (post-init) API example:

someButton.addEventListener(
  'click',
  (interaction) => {
    const { remove } = airgap.overrideCookies({ interaction }, (cookie) => {
      // block all cookies
      cookie.deny();
    });
  },
  { once: true }
);

Cookies can be marked to persist for cross-session replay by setting cookie.persist = true in a cookie override.

Listens to pending requests passively. Returns a cleanup helper with a remove() method.

Listens to pending cookie mutations passively. Returns a cleanup helper with a remove() method.

Clears airgap's request queue and associated caches. Returns true if the operation succeeded.

Resets airgap's request queue and stored tracking consent. If autoReload is true, CSP is active, and consent changes, then the page is also reloaded. Returns true if the operation succeeded.

Serializes and exports airgap's request queues for saving or sending to an analysis endpoint. If report-only mode is enabled, these queues will contain every encountered request. If save is true, the queues are saved locally as airgap-queues.json. If an endpoint URL is specified, the queues are sent via navigator.sendBeacon(). airgap.export() returns the queues as an object. Setting space to a non-zero number enables and sets the indentation level for JSON pretty-printing.

This returns the current semver airgap.js version number from package.json.

Toggles all airgap.js protections. auth must be the airgap.js script 'load' event. Returns true if the protection status was successfully changed, and false otherwise.

Returns the status of airgap.js systems such as protection, event monitoring, and telemetry.

Example output:

{
  "protection": true,
  "csp": false,
  "monitoring": true,
  "telemetry": true
}

This returns the metadata about services being regulated by airgap.js (with a breakdown of cookies vs data flows aka network requests) for each service.

Returns the tracking purpose type configuration metadata. If you want to rename these values, it is suggested that you only rename these visually through a custom UI. 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
  }
}

A helper to clear all cookies matching custom filter provided by the caller.

An example of how this can be used:

const ALWAYS_BLOCK_COOKIES = ['Foo', 'Bar', 'Baz'];
airgap.clearCookies((cookieMutation) =>
  ALWAYS_BLOCK_COOKIES.some((name) => name === cookieMutation)
);

A helper to clear all "disallowed" cookies, based on known cookie classifications, the user's current regional experience, and consent state.

Custom cookie purpose maps can be used by pre-defining airgap.cookies prior to airgap.js init.

Example:

<script>
    self.airgap = {
      cookies: [
        {
          cookie: 'ad_tracker',
          purposes: ['Advertising', 'Analytics'],
        },
        {
          cookie: 'cx_optimization_tracker',
          purposes: ['Analytics'],
        },
        {
          cookie: 'analytics_cookie_but_only_when_its_from_facebook',
          purposes: ['Analytics'],
          hosts: ['facebook.com'],
        },
        {
          cookie: 'essential_cookie',
          purposes: ['Essential'],
        },
      ],
    };
  </>
  <script src=".../airgap.js">
</script>

An object with either a load or interaction field or one of those fields directly. One of the two fields must be validated for authorization with airgap.js. Interaction event time limits (staleness) may be enforced in the future.

/** Airgap authorization proof */
type AirgapAuth =
  | {
      /** A user-initiated interaction event that was just dispatched. */
      interaction?: UIEvent;
      /** A `load` event from a script element that was loaded before or during airgap.js init */
      load?: Event;
    }
  /** A user-initiated interaction event that was just dispatched. */
  | UIEvent
  /** A `load` event from a just-loaded airgap.js script element (which implies auth by being loaded before airgap.js) */
  | Event;

A load event from the just-loaded airgap.js script element.

A user-initiated interaction event that was just dispatched.

/** Tracking purpose consent config */
type TrackingConsent = {
  /** Consent to tracking for essential purposes (required) */
  Essential?: true;
  /** Unknown (unable to be directly consented) */
  Unknown?: false;
  /** Custom tracking purpose */
  [purpose: string]: boolean | undefined;
};
/** Tracking purpose consent config with timestamp & auth metadata */
type TrackingConsentDetails = {
  /** Tracking consent config */
  purposes: TrackingConsent;
  /**
   * Was tracking consent confirmed by the user?
   * If this is false, the consent was resolved from defaults & is not yet confirmed
   */
  confirmed: boolean;
  /** Consent last-modified timestamp (ISO 8601) */
  timestamp: string;
};
/**
 * Request override config
 */
type RequestOverride = {
  /** Optional tracking purposes to gate the override with lack of consent */
  unconsented?: TrackingPurpose[];
  /**
   * Optional request matcher. This is a RegExp object. Overrides apply to
   * all requests when this is undefined.
   */
  matcher?: RegExp;
  /** Override executor function or replacement string */
  override: string | ((request: IPendingEvent, matcher?: RegExp) => void);
};
/**
 * airgap.js pending request interface
 *
 * Pending requests are mutations which will definitely attempt to cause a
 * specific network request.
 *
 * These events can often be replayed cross-session.
 */
interface IPendingRequest {
  /** Request initiator type */
  readonly type: AirgapRequestSource;
  /** Request timestamp (ISO 8601) */
  readonly timestamp: string;
  /** Request URL (mutable for overrides) */
  url: string;
  /** Request URL IPendingMutation interoperability (mutable for overrides) */
  readonly urls: [string];
  /** Will request be persisted for cross-session replay? (override-mutable) */
  persist?: boolean;
  /** Request initialization data */
  requestInit?: RequestInit;
  /**
   * Serialize request or mutation state back to DOM patcher parser input.
   * This is usually a URL, but some mutations have complex multi-URL input.
   * (e.g. img.srcset="/1x.png 1x, /2x.png 2x")
   */
  serialize(): any;
  /** Associated tracking purposes (mutable for overrides) */
  purposes: Set<string>;
  /** Is request allowed? (mutable for overrides) */
  allowed?: boolean | null;

  /** The following IPendingEvent APIs are only available to overrides: */

  /** All associated resolved request URLs */
  URLs: Readonly<URL>[];
  /** Omit credentials (e.g. cookies) from request. Returns success state */
  omitCredentials(): boolean;
  /** Force-allow request */
  allow(): void;
  /** Force-deny request */
  deny(): void;
}

/**
 * airgap.js pending mutation interface
 *
 * Pending mutations are DOM mutations which may cause network requests.
 *
 * These events cannot be replayed cross-session.
 */
type IPendingMutation = Omit<IPendingRequest, 'urls'> & {
  /** Mutation associated URL(s) - Individual URLs are mutable for overrides */
  readonly urls: string[];
};

type IPendingEvent = IPendingRequest | IPendingMutation;
/**
 * airgap.js pending cookie mutation interface
 *
 * Pending cookie mutations are events which will cause a
 * specific cookie to be set.
 *
 * These events can often be replayed cross-session.
 */
interface IPendingCookieMutation {
  /** Cookie name */
  name: string;
  /** Cookie value (null = deletion) */
  value: string | null;
  /** Cookie change event timestamp (ISO 8601 format) */
  timestamp: string;
  /** Expiry date (UTC) */
  expires?: string;
  /** Max cookie age (seconds) */
  maxAge?: number;
  /** Optional cookie host scope */
  domain?: string;
  /** Optional cookie path scope */
  path?: string;
  /** Should cookie only be sent in secure contexts? */
  secure?: boolean;
  /**
   * Should cookie be restricted to the same site?
   * Values: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
   */
  sameSite?: string;
  /** Persist cookie for cross-session replay if quarantined (true by default) */
  persist?: boolean;
  /** Associated tracking purposes */
  purposes: Set<string>;
  /** Is request allowed? */
  allowed?: boolean | null;

  /** The following IPendingCookieMutation APIs are only available to overrides: */
  /** Force-allow mutation */
  allow(): void;
  /** Force-deny mutation */
  deny(): void;
}