# Consent mode

> Hold all tracking and personalization until a visitor accepts, using GeoEngage's compliance banner or your own consent manager.

Set `data-require-consent="true"` on the tag and the widget waits for the visitor's consent:

```html
<script
  src="https://cdn.geoengage.app/ge.js"
  data-api-key="YOUR_API_KEY"
  data-require-consent="true"
></script>
```

Until the visitor accepts, no events, analytics or session recordings are sent, and no rule runs except a **Compliance Banner** rule. The widget does look up the visitor's country and load your published rules, because it needs both to show the banner, worded for the visitor's region. Nothing is recorded for analytics.

The answer is remembered in the visitor's browser, so they're only asked once. Then pick how to ask.

## Option 1: GeoEngage's compliance banner

1. In the dashboard, create a rule with the **Compliance Banner** action.
2. Publish it with **Save & Publish**.

The banner's buttons are already wired up: **Accept** starts tracking and personalization on the spot, and **Reject** keeps everything off.

> [!WARNING]
> The rule has to be published, not just saved. Your site is only ever sent published rules, so without a published Compliance Banner rule there's no banner — and since the banner is the only way to accept, nothing is tracked and no rule runs, for any visitor.

### When consent can't be asked

If consent mode is on but there's no way to ask — no published Compliance Banner rule, or the rules couldn't be loaded — the widget logs a warning to the console, whether or not `data-debug` is set, and fires `geoengage:consent-unavailable` just before `geoengage:awaiting-consent`. You can fall back to a banner of your own:

```js
window.addEventListener('geoengage:consent-unavailable', (event) => {
  // event.detail.reason: 'no_compliance_rule', or 'rules_unavailable' (usually temporary)
  showMyConsentBanner({ onAccept: () => window.GeoEngage.grantConsent() });
});
```

## Option 2: your own consent manager

When the widget is waiting it fires `geoengage:awaiting-consent`. Show your banner then, and call `GeoEngage.grantConsent()` when the visitor accepts:

```js
window.addEventListener('geoengage:awaiting-consent', () => {
  myBanner.show({ onAccept: () => window.GeoEngage.grantConsent() });
});
```

A consent management platform may already know the answer when the page loads, and may report it more than once. Check both ways round, and only grant once. The check below also works in a script that runs before the tag, where there's no `GeoEngage` yet; if the platform answers that early, `geoengage:awaiting-consent` calls it again:

### Cookiebot

```js
function grantIfAllowed() {
  const GeoEngage = window.GeoEngage;
  if (GeoEngage?.hasConsent && !GeoEngage.hasConsent() && window.Cookiebot?.consent?.statistics) {
    GeoEngage.grantConsent();
  }
}

window.addEventListener('geoengage:awaiting-consent', grantIfAllowed);
window.addEventListener('CookiebotOnAccept', grantIfAllowed);
```

### OneTrust

```js
function grantIfAllowed() {
  const GeoEngage = window.GeoEngage;
  // C0002 is OneTrust's default Performance group. Use the group your analytics cookies are in.
  if (GeoEngage?.hasConsent && !GeoEngage.hasConsent() && window.OnetrustActiveGroups?.includes('C0002')) {
    GeoEngage.grantConsent();
  }
}

window.addEventListener('geoengage:awaiting-consent', grantIfAllowed);
window.addEventListener('OneTrustGroupsUpdated', grantIfAllowed);
```

## The consent API

All three can be called as soon as the tag has run. Until the widget checks for consent as it starts, `grantConsent` and `revokeConsent` are held for it, and `hasConsent` answers from what's stored in the visitor's browser.

### `grantConsent`

```ts
GeoEngage.grantConsent(): Promise<void>
```

Records consent in the visitor's browser and starts everything consent mode was holding back: rules, analytics and session recording. It does nothing when consent mode is off.

> [!TIP]
> Check `hasConsent()` before calling it. Consent managers often report the same answer on every page load, and there's nothing to grant twice.

### `revokeConsent`

```ts
GeoEngage.revokeConsent(): void
```

Withdraws consent. Session recording stops at once, and any recording still waiting on the visitor's device to be sent is deleted, so nothing already recorded is uploaded afterwards. Other tracking stops from the next page load rather than mid-page, and the compliance banner asks again then.

```js
document.querySelector('#withdraw-consent').addEventListener('click', () => {
  window.GeoEngage.revokeConsent();
});
```

### `hasConsent`

```ts
GeoEngage.hasConsent(): boolean
```

`true` once the visitor has accepted, and always `true` when consent mode is off.

## Consent events

| Event | When |
| --- | --- |
| `geoengage:consent-unavailable` | Consent mode is on but has no way to ask. `event.detail.reason` says why. |
| `geoengage:awaiting-consent` | The widget is waiting for consent. |
| `geoengage:consent-granted` | `grantConsent()` has started the widget. |
| `geoengage:consent-revoked` | `revokeConsent()` was called. |

Accepting through the compliance banner doesn't fire `geoengage:consent-granted`. It's a `cta-click` [action event](https://geoengage.app/docs/widget/events#the-event-object) with `consent: 'accepted'`.

---

Source: https://geoengage.app/docs/widget/consent
