# airgap.js API Reference (/docs/consent-management/reference/airgap/api)

## Tracking Purpose Resolution [#tracking-purpose-resolution]

airgap.js tags requests with various tracking purposes, coming from your data flows config, any applicable [overrides](#airgapoverrideauth-airgapauth-overrides-requestoverride--remove-void-), and [regulatedPaths](#regulating-specific-requests-and-first-party-tracking) & [regulatedScripts](#regulating-specific-scripts) 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).

Finally, airgap.js compares the request URL with every regulatedPaths filter (and, if the request is a script, every regulatedScript 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.

## Setting and Retrieving User Consent [#setting-and-retrieving-user-consent]

See [How do I set user consent from my website UI?](../../testing-and-troubleshooting/faq.mdx)

## Restoring User Consent From Your Backend [#restoring-user-consent-from-your-backend]

See [Restoring consent to logged-in users from your backend](../../configuration/persist-consent.mdx#restoring-consent-to-logged-in-users-from-your-backend).

## Resetting consent [#resetting-consent]

We generally require `airgap.reset(auth)` to reset consent. As of airgap.js 9.94.0, you can additionally reset consent by disabling XDI sync (with `data-sync-endpoint=""`), clearing local storage, deleting the `tcm` cookie and reloading the page.

Prior to airgap.js 9.94.0, deleting the `tcm` cookie and calling `airgap.sync()` should instantiate a new cookie with default consent, and populate XDI sync with default consent if XDI is being used.

## Consent Events [#consent-events]

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

### `consent-change` Event [#consent-change-event]

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

Example usage:

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

### `consent-resolution` Event [#consent-resolution-event]

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:

```javascript
// 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,
      });
    },
  );
});
```

### `view-state-change` Event [#view-state-change-event]

This is emitted whenever the Transcend Consent Management UI changes state. The list of possible `ViewState`s is published [here](https://github.com/transcend-io/consent-manager-ui/blob/main/README.md#view-states) and has TypeScript types available [here](https://github.com/transcend-io/airgap.js-types/blob/ac1e9cb72f0714c37d743fec1ed0775077d5abe1/src/enums/viewState.ts#L102). Please note that, unlike the other events, you must register the listener for `view-state-change` with `self.transcend` and not `self.airgap`.

Usage:

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

A more complete example:

```javascript
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(),
      });
    },
  );
});
```

### `sync` Event [#sync-event]

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

## Load Options [#load-options]

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:

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

### Unknown Request Policy [#unknown-request-policy]

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: [#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 applicable tracking purposes

### Unknown Cookie Policy [#unknown-cookie-policy]

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 (Default: `on`) [#request-regulation-default-on]

Request regulation uses API patchers to prevent network APIs and network request-generating DOM nodes from making unauthorized requests. Request regulation can be disabled by setting `data-protect="off"` on your airgap.js script tag.

### Cookie Regulation (Default: `on`) [#cookie-regulation-default-on]

Cookie regulation uses 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.

### Navigation Control (Default: `off`) [#navigation-control-default-off]

[Navigation control](../navigation-control.mdx) uses a combination of request regulation API patchers and the Navigation API to prevent unauthorized automated navigation using JS APIs. Navigation control can be enabled by setting `data-regulate-navigation="on"` on your airgap.js script tag.

### CSP Protection [#csp-protection]

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](#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"`

### Extending Generated CSPs [#extending-generated-csps]

Generated CSPs can be extended by specifying `self.airgap.csp` prior to airgap.js init, following this format:

```javascript
self.airgap = {
  csp: {
    'example-csp-rule-1': [
      'AssociatedTrackingPurpose1',
      'AssociatedTrackingPurpose2',
    ],
    'example-csp-rule-2': ['Essential'],
  },
};
```

For the above example, generated CSPs will additionally include both `example-csp-rule-1` and `example-csp-rule-2` in lax mode. In strict mode, the generated CSP will include rules based on user consent to associated rule tracking purposes.

### Disable airgap.js Protections When Fully Consented (Default: `on`) [#disable-airgapjs-protections-when-fully-consented-default-on]

In order to optimize performance, airgap.js automatically disables protections (including DOM patchers and Content Security Policy) when users are fully consented, unless any event overrides are registered. When this mode is enabled, airgap.js will automatically enable protections as needed whenever tracking consent changes. This feature can be turned off by setting `data-disable-when-consented="off"` on your airgap.js script tag.

### Default Privacy Legal Regime (Default: `"Unknown"`) [#default-privacy-legal-regime-default-unknown]

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.

### Forcing Legal Regime [#forcing-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 semicolons.

### Automatically Refresh Page on Consent Change When CSP is Active (Default: `on`) [#automatically-refresh-page-on-consent-change-when-csp-is-active-default-on]

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"`).

### Automatically Displaying the Consent Prompt UI (Default: `off`) [#automatically-displaying-the-consent-prompt-ui-default-off]

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`.

### Automatically Expiring Consent (Default: `off`) [#automatically-expiring-consent-default-off]

Consent expiry can be triggered after a certain expiration time limit by setting `data-consent-expiry=[# of minutes]`. For example, setting `consent-expiry=518400` will cause consent to automatically expire in a year.

### Consent Expiry Action (Default: `Prompt`) [#consent-expiry-action-default-prompt]

The behavior determining how airgap.js behaves when consent expires can be configured through the `data-on-consent-expiry` attribute. The default behavior is to prompt the user to re-consent. The following options are available:

- `Prompt` — Prompt the user to re-confirm consent (default)
- `ResetOptIns` — Reset all opted-in purposes to default
- `Reset` - Reset all consent to default

### Automatically Expiring Quarantined Events (Default: `off`) [#automatically-expiring-quarantined-events-default-off]

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.

### Self-Host Transcend Consent [#self-host-transcend-consent]

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](../self-hosting.mdx#javascript-modules).

### Using an External Stylesheet [#using-an-external-stylesheet]

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](https://github.com/transcend-io/consent-manager-ui) to clone, modify and host as well.

### Customizing Privacy Policy Links [#customizing-privacy-policy-links]

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](https://github.com/transcend-io/consent-manager-ui#completeoptionsinverted) view state also uses the `data-secondary-policy` data attribute to display a secondary policy link.

### Customize Available Languages in Consent Prompts [#customize-available-languages-in-consent-prompts]

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](https://github.com/transcend-io/tools/blob/88d7a37ac71c2205e239941f6ffea27fd6a32fb3/packages/internationalization/src/enums.ts#L4).

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')`.

### Customizing Consent Prompt UI Script [#customizing-consent-prompt-ui-script]

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](../../configuration/consent-ui/creating-your-own-ui.mdx).

### Enable Additional Debugging Features [#enable-additional-debugging-features]

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](../../testing-and-troubleshooting/debugging-and-testing.mdx#useful-commands).

### Request Monitoring (Default: `on`) [#request-monitoring-default-on]

_\*Default of on only if telemetry or report-only mode is on_

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()](#airgapwatchwatcher-request-readonlyipendingevent--void--remove-void-).

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.

### Dismissed View State (Default: `"Collapsed"`) [#dismissed-view-state-default-collapsed]

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.

### Tamper Resistance (Default: `off`) [#tamper-resistance-default-off]

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

Read more: [Security: Tamper resistance](../privacy-and-security.mdx#tamper-resistance)

### Report-Only Mode (Default: `off`) [#report-only-mode-default-off]

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.

### Telemetry (Default: `on`) [#telemetry-default-on]

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:

```json
{
  "site": "example.com",
  "entries": {
    "https://example.com": {
      "hosts": "example.com 5\ntranscend-cdn.com\nexample.org 2\nwss:uses-websockets.example 4"
    }
  }
}
```

Host encounter tally format (`.hosts`):

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

### Change the Bounce Debouncer Interaction Threshold [#change-the-bounce-debouncer-interaction-threshold]

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.

### Consent & Quarantine Sync Endpoint (Default: \[server-provided bundle-specific URL]) [#consent--quarantine-sync-endpoint-default-server-provided-bundle-specific-url]

airgap.js can sync consent & quarantine data privately cross-domain over the [Transcend XDI](../xdi.mdx) 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.

### Sync (Default: `on`) [#sync-default-on]

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.

### Deferring Initial Sync (Default: `off`) [#deferring-initial-sync-default-off]

If sync is enabled, then airgap.js will immediately attempt to sync consent state on initial load. To defer this initial sync, set `data-defer-sync="off"`. This is useful for sites where the customer wants more control over sync timing and to avoid creating extra requests.

### Console Logging (Default: `warn error`) [#console-logging-default-warn-error]

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="warn error"`) 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 `"warn error"`.

### Replay Control (Default: `on`) [#replay-control-default-on]

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.

### Disable airgap.js (Default: `off`) [#disable-airgapjs-default-off]

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

## Airgap Pre-init Configuration [#airgap-pre-init-configuration]

### Regulating Specific Scripts [#regulating-specific-scripts]

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.

```typescript
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;
}
```

### Regulating Specific Requests and First-Party Tracking [#regulating-specific-requests-and-first-party-tracking]

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.

### Preventing Cookies From Being Included in Specific Requests [#preventing-cookies-from-being-included-in-specific-requests]

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.

## airgap.js API Reference [#airgapjs-api-reference]

### Methods [#methods]

#### `airgap.isAllowed(url: string, resolveOverrides = true): Promise<boolean>` [#airgapisallowedurl-string-resolveoverrides--true-promiseboolean]

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

#### `airgap.isRequestAllowed(request: IPendingRequest | string, resolveOverrides = true): Promise<boolean>` [#airgapisrequestallowedrequest-ipendingrequest--string-resolveoverrides--true-promiseboolean]

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

#### `airgap.isCookieAllowed(cookie: IPendingCookieMutation | string, resolveOverrides = true): Promise<boolean>` [#airgapiscookieallowedcookie-ipendingcookiemutation--string-resolveoverrides--true-promiseboolean]

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

#### `airgap.getPurposes(url: string, resolveOverrides = true): Promise<Set<TrackingPurpose>>` [#airgapgetpurposesurl-string-resolveoverrides--true-promisesettrackingpurpose]

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

#### `airgap.getRequestPurposes(request: IPendingRequest | string, resolveOverrides = true): Promise<Set<TrackingPurpose>>` [#airgapgetrequestpurposesrequest-ipendingrequest--string-resolveoverrides--true-promisesettrackingpurpose]

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

#### `airgap.getCookiePurposes(cookie: IPendingCookieMutation | string, resolveOverrides = true): Promise<Set<TrackingPurpose>>` [#airgapgetcookiepurposescookie-ipendingcookiemutation--string-resolveoverrides--true-promisesettrackingpurpose]

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

#### `airgap.getRegimes(): Set<string>` [#airgapgetregimes-setstring]

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.

#### `airgap.getRegimePurposes(regimes = airgap.getRegimes()): Set<string>` [#airgapgetregimepurposesregimes--airgapgetregimes-setstring]

Returns a set of all tracking purposes indicated as applicable for the selected regimes.

**Example**

Detecting GDPR and CCPA/CPRA-protected users:

```tsx
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
}
```

#### `airgap.protect(node?: Node): ({ remove(): void })` [#airgapprotectnode-node--remove-void-]

Protects a node's realm using API patchers and DOM protection mechanisms. Defaults to `document`. Returns an object with a removal function to disable DOM protection if the target realm was newly protected by the corresponding `airgap.protect(...)` call.

#### `airgap.activateCSP(policy?: CSPPolicyDirective[]): Promise<void>` [#airgapactivatecsppolicy-csppolicydirective-promisevoid]

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.

#### `airgap.ready()` [#airgapready]

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

#### `airgap.sync(options?: SyncOptions): Promise<void>` [#airgapsyncoptions-syncoptions-promisevoid]

Enqueues a cross-domain data sync across all Transcend Consent Management allowed domains and resolves when sync is complete. Boolean options such as `local` and `backend` control whether to use local (XDI / cookies) and remote sync methods. The `auth` option represents a key used for associating remotely synchronized consent records.

#### `airgap.getConsent(): TrackingConsentDetails` [#airgapgetconsent-trackingconsentdetails]

Returns the user's current tracking consent details.

#### `airgap.setConsent(auth: AirgapAuth, consent: TrackingConsent): boolean` [#airgapsetconsentauth-airgapauth-consent-trackingconsent-boolean]

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.

#### `airgap.optIn(auth: AirgapAuth): boolean` [#airgapoptinauth-airgapauth-boolean]

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

#### `airgap.optOut(auth: AirgapAuth): boolean` [#airgapoptoutauth-airgapauth-boolean]

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

#### `airgap.isOptedIn(): boolean` [#airgapisoptedin-boolean]

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()](#airgapgetpurposetypes-trackingpurposestypes)

#### `airgap.isOptedOut(): boolean` [#airgapisoptedout-boolean]

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()](/)

#### `airgap.override(auth: AirgapAuth, ...overrides: RequestOverride[]): ({ remove(): void })` [#airgapoverrideauth-airgapauth-overrides-requestoverride--remove-void-]

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:

```javascript
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:

```javascript
airgapScript.addEventListener(
  'load',
  (load) => {
    const { remove } = airgap.override(
      { load },
      {
        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 },
);
```

##### Replay Persistence Configurability [#replay-persistence-configurability]

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

##### Replay Persistence Example [#replay-persistence-example]

```javascript
// prior to loading airgap.js
const noPersistHosts = new Set(['fresnel.vimeocdn.com' /*  ... */]);
(self.airgap = {
  overrides: [],
  ...self.airgap
}).overrides.push({
  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;
    }
  },
});
```

#### `airgap.overrideCookies(auth: AirgapAuth, ...overrides: ((cookie: IPendingCookieMutation) => void)[]): ({ remove(): void })` [#airgapoverridecookiesauth-airgapauth-overrides-cookie-ipendingcookiemutation--void--remove-void-]

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:

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

Runtime (post-init) API example:

```javascript
airgapScript.addEventListener(
  'load',
  (load) => {
    airgap.overrideCookies({ load }, (cookie) => {
      // block all cookies
      cookie.block();
    });
  },
  { once: true }
);
```

##### Replay Persistence Configurability [#replay-persistence-configurability-1]

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

#### `airgap.watch(watcher: (request: Readonly<IPendingEvent>) => void): ({ remove(): void })` [#airgapwatchwatcher-request-readonlyipendingevent--void--remove-void-]

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

#### `airgap.watchCookies(watcher: (cookie: Readonly<IPendingCookieMutation>) => void): ({ remove(): void })` [#airgapwatchcookieswatcher-cookie-readonlyipendingcookiemutation--void--remove-void-]

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

#### `airgap.clear(auth: AirgapAuth): boolean` [#airgapclearauth-airgapauth-boolean]

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

#### `airgap.reset(auth: AirgapAuth, autoReload?: boolean): boolean` [#airgapresetauth-airgapauth-autoreload-boolean-boolean]

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.

#### `airgap.export({save?: boolean, endpoint?: string, filename?: string, space:? number}): void | object` [#airgapexportsave-boolean-endpoint-string-filename-string-space-number-void--object]

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.

#### `airgap.version: string` [#airgapversion-string]

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

#### `airgap.toggle(auth: AirgapAuth, protection?: boolean): boolean` [#airgaptoggleauth-airgapauth-protection-boolean-boolean]

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.

#### `airgap.status` [#airgapstatus]

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

Example output:

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

#### `airgap.getMetadata(): Promise<JSON>` [#airgapgetmetadata-promisejson]

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.

#### `airgap.getPurposeTypes(): TrackingPurposesTypes` [#airgapgetpurposetypes-trackingpurposestypes]

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:

```json
{
  "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
  }
}
```

#### `airgap.clearCookies(filter: (cookie: IPendingCookieMutation) => boolean): Promise<void> | void` [#airgapclearcookiesfilter-cookie-ipendingcookiemutation--boolean-promisevoid--void]

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

An example of how this can be used:

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

#### `airgap.clearDisallowedCookies(): Promise<void> | void` [#airgapcleardisallowedcookies-promisevoid--void]

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

### Force-allowing/denying/blocking events [#force-allowingdenyingblocking-events]

The `IPendingEvent.{allow, deny, block}()` API allows event overrides to force the allowed or blocked state for an event. `allow()`/`deny()` sets the `allowed` state to `true`/`false` and `block()` sets the allowed state to `false` and the `blocked` state to `true`. Blocked events cannot be unblocked.

Event force-allowed/denied/blocked state can be inspected through the `IPendingEvent.{allowed: boolean | null, blocked: boolean}` accessors. When `event.allowed` is set to `null`, we re-resolve consent on subsequent accesses to `event.allowed`. If force-allow state has been explicitly set to `true` or `false`, then the state is not re-resolved upon subsequent accesses.

### Custom Cookie Purpose Map [#custom-cookie-purpose-map]

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

**Example:**

```html
<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>
```

### Core API Types [#core-api-types]

#### `AirgapAuth` [#airgapauth]

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.

```tsx
/** 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;
```

#### `.load` [#load]

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

#### `.interaction` [#interaction]

A user-initiated interaction event that was just dispatched.

#### `TrackingConsent` [#trackingconsent]

```tsx
/** 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;
};
```

#### `TrackingConsentDetails` [#trackingconsentdetails]

```tsx
/** 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;
};
```

#### `RequestOverride` [#requestoverride]

```tsx
/**
 * 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);
};
```

#### `IPendingEvent` [#ipendingevent]

```tsx
/**
 * 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;
  /** Should request be disallowed and blocked from quarantine? (mutable to true for overrides; cannot be changed once set) */
  blocked?: boolean;

  /** 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;
  /** Force-deny and block request from entering quarantine */
  block(): 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;
```

#### `IPendingCookieMutation` [#ipendingcookiemutation]

```tsx
/**
 * 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 cookie mutation allowed? */
  allowed?: boolean | null;
  /** Should cookie mutation be disallowed and blocked from quarantine? (mutable to true for overrides; cannot be changed once set) */
  blocked?: boolean;

  /** The following IPendingCookieMutation APIs are only available to overrides: */
  /** Force-allow mutation */
  allow(): void;
  /** Force-deny mutation */
  deny(): void;
  /** Force-deny and block mutation from entering quarantine */
  block(): void;
}
```
