# Kibble installation contract: section 10 of 29 (guide version 3)

> This is **one section only**, not the whole contract. Complete document: https://www.usekibble.dev/AI/guide.md

## 10. Consent {#consent}

The SDK collects nothing until it is told consent is granted. Wire the site's banner or consent platform to it, and re-apply the stored choice on every page load, because the SDK does not remember consent for you.

Manual consent:

```js
// when the visitor chooses
kibble('consent', 'granted');   // start collecting
kibble('consent', 'denied');    // stop immediately, purge queued events, delete the stored browser id

// on every page load, before or right after the snippet, re-apply the saved choice
try {
  var c = localStorage.getItem('YOUR_CONSENT_KEY');
  if (c === 'granted' || c === 'denied') kibble('consent', c);
} catch (e) {}

// "Forget my data" control
await kibble('forget');         // withdraws consent, deletes the browser id and requests erasure
```

- Events that happen while consent is unknown or denied are not captured, so nothing is replayed after a later grant.
- Page performance needs the stored choice applied before the SDK starts on the page: queue `kibble('consent', 'granted')` with the snippet, or push the Consent Mode state to `dataLayer` before the SDK loads. A grant that arrives later (a click on the banner, or a consent platform that loads after Kibble) starts collection normally, but that one page load has no performance measurement.
- `forget` also sends an erasure request. If that request fails, the SDK keeps a pending erasure in `localStorage` and retries it on later page loads for up to seven days, even before consent is granted.

### Google Consent Mode

Set `data-consent="google-consent-mode"`. The SDK follows `analytics_storage` from the `consent` default and update commands pushed to `dataLayer`, including ones pushed before it loaded. `granted` starts collection and `denied` withdraws it. Other consent keys are ignored.

```js
gtag('consent', 'default', { analytics_storage: 'denied' });
// later, from your banner
gtag('consent', 'update', { analytics_storage: 'granted' });
```

Do not map advertising consent to Kibble. Only the analytics purpose applies.

### Consent platforms chosen in Kibble (key-only installations)

A key-only installation (the standard GTM tag, [Google Tag Manager](https://www.usekibble.dev/AI#gtm)) follows the consent source a Kibble staff member chose for the property. There are four, and nothing else is offered. Each reads the platform's own browser state and fails closed: nothing is collected until a grant is observed, a malformed value or two values that disagree count as no decision, and a later non-grant (or the choice disappearing) is a withdrawal that stops collection, purges the queue and deletes the stored browser id. Each is tested against the platform's documented browser API with fixtures; none is verified on a live site.

| Source | What is read | Re-checked |
| --- | --- | --- |
| Google Consent Mode (default) | `analytics_storage` from the `consent` default and update commands in `dataLayer`, as above | On every consent command |
| TrustArc | The `cmapi_cookie_privacy` cookie (`permit 1,2,3 …`): granted when the analytics category is listed. The category number is set in Kibble (default 2) | On TrustArc's preference messages, clicks, focus, tab return and page show |
| OneTrust | `window.OnetrustActiveGroups` once OneTrust has loaded, else the groups in the `OptanonConsent` cookie: granted when the analytics group is active. The group id is set in Kibble (default `C0002`) | On `OneTrustGroupsUpdated` (window event or dataLayer), focus, tab return and page show |
| CookieYes | `getCkyConsent().categories`, else the `cookieyes-consent` cookie (`analytics:yes`): the category is set in Kibble (default `analytics`) | On `cookieyes_consent_update` and `cookieyes_banner_load`, focus, tab return and page show |

If OneTrust or CookieYes also publishes Google Consent Mode on the site, choose Google Consent Mode. A page that sets `data-consent` keeps its own consent wiring and never reads these settings.

Consent is per host and never inferred. Each host that runs the snippet asks for it and withdraws it separately. A click on a link, a link decorated for cross-domain continuity or a `_kbh` token in the address does not grant it: the destination holds the token until its own consent source grants. On a provider's host (a booking engine or checkout) the consent source is that host's own: the provider's consent tooling, a tag manager's Consent Mode, or for Shopify the customer privacy API. The website's consent cookie is not readable there. If none can be wired, collect nothing and report the gap.

END OF SECTION consent
