# Consent banners and the referral tag

Where a referral cookie needs consent, the tag waits for your banner: one attribute, one call, and a snippet for each consent tool.

Where the law needs a visitor's consent before a referral cookie is stored, Bolt
Claw's website tag waits for your consent banner: one attribute on the tag, one
call from the banner. Below are a short helper, a snippet for each common consent
tool, and a paragraph for your own cookie policy.

This page explains what the tag does. It is not legal advice: whether you need
consent, and for which visitors, is for you and your adviser to decide.

## When you need it

- **The EU.** Storing anything on a visitor's device, or reading it from there,
  needs their consent unless it is strictly necessary for a service they asked for
  (Article 5(3) of the ePrivacy Directive). France's CNIL says in question 13 of its
  cookie FAQ that trackers used to bill affiliate operations are **not** exempt.
- **The UK.** The ICO takes the same position on affiliate click and conversion
  tracking, under regulation 6 of PECR.
- **One possible exception.** The CNIL's question 14 accepts that trackers needed
  for a cashback or reward scheme the visitor joined may be exempt. That is about a
  reward the visitor asked for, not a partner's commission; take advice before you
  rely on it.
- **Elsewhere,** other laws may ask for a notice or an opt-out instead.

On the program's **Integration** tab, **Edit answers**, turn on **Our audience
includes the EU or the UK**. The tags the Integration and Welcome tabs then give you
carry `data-consent="required"`, and the setup status warns you if the tag it sees
on your site does not wait for consent.

## What the tag stores

Everything is first-party, on your own domain. The tag sets nothing on
`boltclaw.ai`, creates no visitor id and reads only what it wrote.

| Name | Kind | Holds | For |
|---|---|---|---|
| `bc_ref` | Cookie, and a `localStorage` copy | The partner's referral code | The program's cookie window |
| `bc_click` | Cookie, and a `localStorage` copy | The click id from the link (16 random letters and digits) | The cookie window |
| `bc_sub` | Cookie, and a `localStorage` copy | The partner's campaign tag, when the link has one | The cookie window |
| `bc_welcome_dismissed:<code>` | `localStorage` | `1`, once the visitor closes the welcome | Until the visitor clears it |

The cookie window is the program's **Cookie window (days)** on its Settings tab, 1
to 365 and 30 unless you changed it. Each cookie is `Path=/`, `SameSite=Lax` and,
on https, `Secure`. The copy is there because some in-app browsers drop cookies
between pages; an expired copy is deleted when the tag next reads it.

## Consent mode

Add one attribute to the tag:

```html
<script src="https://boltclaw.ai/referrals/v2.js" defer
        data-consent="required"></script>
```

**Before the visitor answers,** the tag reads the code, click id and campaign tag
from the address and keeps them in the page's memory only. It stores nothing,
reads nothing it stored before, makes no request, leaves Stripe Payment Links alone,
draws no welcome, and `BoltClawReferral.offer()` waits. `code()`, `clickId()`,
`sub()`, `clientReferenceId()` and `attach(form)` still give that page's values, so
a form sent from the landing page can carry them; if you would rather not, call
them only after consent.

**`BoltClawReferral.consent(true)`** when the visitor accepts: the tag stores what
the page read (by the program's first-click or last-click rule), reads what it
stored after an earlier consent, and turns on the welcome, the offer and Payment
Links if you use them.

**`BoltClawReferral.consent(false)`** when the visitor refuses or withdraws: the
tag forgets what the page read and neither reads nor writes storage on that page
unless they accept later. It does not delete what it stored on an earlier page;
the helper below does.

Four rules:

- **Tell the tag on every page.** It does not remember the answer between pages;
  your consent tool does. Every snippet below reads the saved answer as each page
  loads.
- **Never call `consent(false)` before the visitor answers.** It forgets the code,
  and a later `consent(true)` on the same page has nothing left to store. While
  they have not answered, call nothing.
- **Never define `window.BoltClawReferral` yourself,** not even as a stub: the tag
  finds it there and does not start.
- **Calls are safe to repeat,** and without `data-consent="required"` the tag
  ignores them. Version 1 (`v1.js`) has no consent mode; use `v2.js`.

## The helper

Put this right after the tag, in the `<head>`, before your consent tool's own
script where you can. It is the same for every tool: it passes the answer to the
tag even when your consent tool answers before the tag has loaded, and on a
refusal or withdrawal it deletes what the tag stored.

```html
<script src="https://boltclaw.ai/referrals/v2.js" defer
        data-consent="required"></script>
<script>
  (function () {
    var NAMES = ["bc_ref", "bc_click", "bc_sub"];
    var answer = null;
    function tell() {
      if (answer !== null && window.BoltClawReferral) window.BoltClawReferral.consent(answer);
    }
    function forget() {
      NAMES.forEach(function (name) {
        document.cookie = name + "=; Path=/; Max-Age=0; SameSite=Lax";
      });
      try {
        for (var i = localStorage.length - 1; i >= 0; i--) {
          var key = localStorage.key(i) || "";
          if (NAMES.indexOf(key) !== -1 || key.indexOf("bc_welcome_dismissed:") === 0) {
            localStorage.removeItem(key);
          }
        }
      } catch (e) {}
    }
    // true: the visitor accepted. false: they refused or withdrew. Only once they answer.
    window.boltclawConsent = function (granted) {
      answer = granted === true;
      tell();
      if (!answer) forget();
    };
    document.addEventListener("DOMContentLoaded", tell);
    window.addEventListener("load", tell);
  })();
</script>
```

Then add your tool's snippet below it. Each one names the category to put the tag
in: list `bc_ref`, `bc_click` and `bc_sub` there in your tool's cookie list, by
hand if its scan does not find them (a scan sees them only on a page opened from a
referral link).

## Cookiebot

Category: **Marketing**.

```html
<script>
  function boltclawFromCookiebot() {
    if (!window.Cookiebot || !Cookiebot.consent) return;
    if (Cookiebot.consent.marketing) boltclawConsent(true);
    else if (Cookiebot.consented || Cookiebot.declined) boltclawConsent(false);
  }
  window.addEventListener("CookiebotOnConsentReady", boltclawFromCookiebot);
  document.addEventListener("DOMContentLoaded", boltclawFromCookiebot);
</script>
```

`CookiebotOnConsentReady` fires when the answer is loaded from an earlier visit and
whenever the visitor submits one; `Cookiebot.consented` or `Cookiebot.declined` is
true only once they have answered.

## OneTrust

Category: **Targeting Cookies**, group `C0004` in OneTrust's default set. If you
put the tag in a group of your own, use its id instead.

```html
<script>
  function boltclawFromOneTrust(groups) {
    if (("," + groups + ",").indexOf(",C0004,") !== -1) boltclawConsent(true);
    else if (window.OneTrust && typeof OneTrust.IsAlertBoxClosed === "function" && OneTrust.IsAlertBoxClosed()) {
      boltclawConsent(false);
    }
  }
  window.addEventListener("OneTrustGroupsUpdated", function (event) {
    boltclawFromOneTrust((event.detail || []).join(","));
  });
  document.addEventListener("DOMContentLoaded", function () {
    if (typeof window.OnetrustActiveGroups === "string") boltclawFromOneTrust(OnetrustActiveGroups);
  });
</script>
```

`OneTrustGroupsUpdated` fires as OneTrust loads and whenever the visitor changes
their choice, with the active group ids; `OneTrust.IsAlertBoxClosed()` is true once
they have answered.

## Usercentrics

Category: **Marketing**. In the Usercentrics admin, add Bolt Claw as a custom
service in the Marketing category, named exactly **Bolt Claw Referrals**, with the
three cookies. This uses the Web CMP v3 event `UC_CONSENT`, which fires as the page
loads (with the saved answer) and after every change.

```html
<script>
  window.addEventListener("UC_CONSENT", function (event) {
    var detail = event.detail || {};
    var services = detail.services || {};
    for (var id in services) {
      if (services[id].name !== "Bolt Claw Referrals") continue;
      if (services[id].consent && services[id].consent.given) boltclawConsent(true);
      else if (detail.consent && detail.consent.type === "EXPLICIT") boltclawConsent(false);
    }
  });
</script>
```

A consent of type `EXPLICIT` is one the visitor gave; before that, the service's
default is not an answer, so nothing is called.

## CookieYes

Category: **Advertisement** (`advertisement`; CookieYes's events use the original
category ids even if you renamed the category).

```html
<script>
  function boltclawFromCookieYes(consent) {
    if (consent.categories && consent.categories.advertisement) boltclawConsent(true);
    else if (consent.isUserActionCompleted) boltclawConsent(false);
  }
  document.addEventListener("cookieyes_banner_load", function (event) {
    boltclawFromCookieYes(event.detail || {});
  });
  document.addEventListener("cookieyes_consent_update", function (event) {
    var accepted = (event.detail && event.detail.accepted) || [];
    boltclawFromCookieYes({
      categories: { advertisement: accepted.indexOf("advertisement") !== -1 },
      isUserActionCompleted: true,
    });
  });
  document.addEventListener("DOMContentLoaded", function () {
    if (typeof window.getCkyConsent === "function") boltclawFromCookieYes(getCkyConsent() || {});
  });
</script>
```

`cookieyes_banner_load` carries the saved answer as the banner loads (and
`getCkyConsent()` returns it once the banner has loaded), and
`cookieyes_consent_update` each new one. CookieYes's WordPress plugin sends these
events only when it is connected to the CookieYes web app; on WordPress you can use
the WP Consent API instead (below).

## Klaro

Purpose: **marketing**, as in Klaro's own example configuration (add a translation
for it if your configuration has none). Add this service to the `services` list in
your Klaro configuration, and load the helper above before Klaro's own script,
because Klaro calls the service's `callback` as soon as it starts:

```js
{
  name: "boltclaw-referrals",
  title: "Bolt Claw referrals",
  purposes: ["marketing"],
  cookies: ["bc_ref", "bc_click", "bc_sub"],
  callback: function (consent, service) {
    if (consent) boltclawConsent(true);
    else if (service.boltclawAccepted) boltclawConsent(false);
    service.boltclawAccepted = consent;
  },
},
```

Klaro calls `callback` with `false` before the visitor has answered as well as
after a refusal, so this passes on a "no" only after an earlier "yes"; until then
the tag keeps waiting, which stores nothing. Klaro deletes the listed cookies itself
when consent is withdrawn.

## Shopify

**With Bolt Claw's Shopify app** there is nothing to add: switch on the app embed,
and keep **Wait for the visitor's consent** on (the default). It passes the
visitor's marketing choice from Shopify's own cookie banner to the tag. See
[Referrals for Shopify](https://boltclaw.ai/docs/referral-shopify).

**Without the app** (the tag in your theme yourself), use Shopify's Customer
Privacy API. Category: **marketing** (`marketingAllowed`: marketing, attribution
and targeted advertising). In `theme.liquid`, put the tag, the helper and this
after `{{ content_for_header }}`.

```html
<script>
  function boltclawFromShopify() {
    var privacy = window.Shopify && window.Shopify.customerPrivacy;
    if (!privacy) return;
    if (privacy.marketingAllowed()) boltclawConsent(true);
    else if (privacy.currentVisitorConsent().marketing === "no") boltclawConsent(false);
  }
  document.addEventListener("visitorConsentCollected", boltclawFromShopify);
  if (window.Shopify && window.Shopify.loadFeatures) {
    window.Shopify.loadFeatures([{ name: "consent-tracking-api", version: "0.2" }], function (error) {
      if (!error) boltclawFromShopify();
    });
  }
</script>
```

`currentVisitorConsent().marketing` is `"yes"`, `"no"`, or `""` while the visitor
has not answered.

## WordPress: the WP Consent API

**With Bolt Claw's WooCommerce plugin** there is nothing to add: when a consent
plugin that supports the WP Consent API is active, the plugin turns consent mode on,
registers the three cookies under **marketing**, and passes the answer to the tag.
See [Referrals for WooCommerce](https://boltclaw.ai/docs/referral-woocommerce).

**Without it,** with the tag in your theme and a consent plugin that supports the
WP Consent API: category **marketing**.

```html
<script>
  function boltclawFromWordPress() {
    if (typeof window.wp_has_consent === "function" && wp_has_consent("marketing")) {
      boltclawConsent(true);
    }
  }
  document.addEventListener("wp_consent_type_defined", boltclawFromWordPress);
  document.addEventListener("DOMContentLoaded", boltclawFromWordPress);
  document.addEventListener("wp_listen_for_consent_change", function (event) {
    var changed = event.detail || {};
    if (changed.marketing === "allow") boltclawConsent(true);
    else if (changed.marketing === "deny") boltclawConsent(false);
  });
</script>
```

## Your own banner, or another tool

Call `boltclawConsent(true)` when the visitor accepts the category you put the tag
in, and `boltclawConsent(false)` when they refuse it or withdraw. For a visitor who
answered on an earlier visit, call it with their saved answer as each page loads.
While they have not answered, call nothing.

## Check it

1. Open your site in a private window with `?via=` and one of your partners' codes.
2. Before you answer the banner, your browser's developer tools (Application,
   Cookies) show no `bc_ref`.
3. Accept: `bc_ref` appears, for the program's cookie window. Open another page:
   it is still there, and `BoltClawReferral.code()` in the console returns the code.
4. Withdraw consent in your tool: `bc_ref`, `bc_click` and `bc_sub` are gone.

The Integration tab's setup status also says whether the tag it sees waits for
consent. For a tag added by a tag manager, open your site with the setup status's
verify link.

## A paragraph for your cookie policy

Paste this into your own cookie policy, replacing `{{cookieDays}}` with the
program's cookie window. Adapt it as you need; your policy stays yours.

> Referral cookies. If you arrive on our website through a link from one of our referral partners, we use Bolt Claw's referral tag to remember which partner sent you, so that we can reward them if you sign up or buy and check that the referral is genuine. It stores the partner's referral code, a random number for that click and, if the partner added one, the name of their campaign, in cookies named `bc_ref`, `bc_click` and `bc_sub` on our own website, with a copy of each in your browser's local storage, for {{cookieDays}} days. If you close the welcome message the tag can show, it also remembers that in local storage. Bolt Claw sets no cookie of its own, and these cookies hold no name or email address. Where the law requires it, we store them only after you agree to marketing cookies, and you can change your choice at any time in our cookie settings.

<!-- https://boltclaw.ai/docs/referral-consent as markdown. Generated from openapi.yaml; API version 1.22.0. -->
<!-- Every /docs page answers as markdown: add .md to its path, or send Accept: text/markdown. -->
