> For the complete documentation index, see [llms.txt](https://docs.momocode.de/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.momocode.de/en/shopware-6/advanced-wishlists/4.-consent.md).

# 4. Consent & Consent Tools

The guest wishlist stores products in the visitor's browser (`localStorage`), which makes it subject to consent. You decide where the plugin reads that consent from — from Shopware's own cookie banner through to an integration with an external consent management platform (CMP).

All settings on this page are found at **Extensions → My Extensions → Advanced Wishlists → ··· → Configure**.

> This page applies to **guest visitors** only. Logged-in customers store their wishlists server-side in their customer account, where no consent check applies.

***

## Choosing the Consent Source

The **Consent source** field in the **Guest Wishlist** section determines where the consent state comes from:

| Consent source                               | Consent comes from                                                         | Plugin cookie in Shopware's banner |
| -------------------------------------------- | -------------------------------------------------------------------------- | ---------------------------------- |
| **Shopware cookie banner** *(default)*       | Shopware's own cookie banner, category "Functional"                        | yes                                |
| **Foreign cookie (consent management tool)** | A cookie set by your consent tool, evaluated via a configurable comparison | no                                 |
| **Custom (JavaScript API)**                  | A small JavaScript snippet in your theme only                              | no                                 |
| **No consent check**                         | Nowhere — the guest wishlist is active without any check                   | no                                 |

Two points that regularly cause questions:

* **The setting applies shop-wide**, not per sales channel. Shopware calls the plugin's cookie provider without a sales channel context, so a per-channel setting could not be honoured there. To make sure the cookie banner and the storefront never disagree, both read the same global value.
* **The "Enable guest wishlist" setting always wins.** If the guest wishlist is disabled, it is off in all four sources. The consent source only decides *how* consent is detected — never *whether* the feature exists at all.

In every source other than **Shopware cookie banner**, the plugin deliberately stops declaring its cookie in Shopware's cookie banner. Otherwise the banner would list a cookie the storefront never uses.

***

## Shopware Cookie Banner (Default)

With no further configuration, the plugin cookie appears in Shopware's cookie banner under **Functional**. When a visitor accepts that category, the guest wishlist is enabled **immediately** — no page reload or navigation required. The wishlist control appears right after the cookie selection is saved.

For most shops this is the right choice and no additional settings are needed.

***

## Foreign Cookie (Consent Management Tool)

If you use a consent management platform instead of Shopware's banner, the plugin can read its cookie directly. Three fields control this:

| Field                                            | Meaning                                                            |
| ------------------------------------------------ | ------------------------------------------------------------------ |
| **Consent cookie name**                          | The cookie to read, e.g. `CookieConsent`                           |
| **Consent cookie match strategy**                | Exact match, Contains, or JSON path                                |
| **Consent cookie comparison value or JSON path** | The comparison value — or, for JSON path, the path into the cookie |

The three match strategies:

* **Exact match** — The cookie value equals the comparison value exactly (case-sensitive).
* **Contains** — The comparison value appears somewhere in the cookie value. This is the right strategy for tools whose cookie is readable text rather than valid JSON.
* **JSON path** — The cookie value is parsed as JSON and the comparison value is followed as a dot-separated path (e.g. `consents.comfort`). Only `true`, `1`, `"1"` or `"true"` count as granted.

### Recipes for Common Consent Tools

Cookie names and structures are defined by the vendors of the consent tools and can change with any release. The values below are **starting points, not guarantees** — verify them against your own installation using your browser's developer tools.

| Tool           | Consent source | Cookie                          | Match strategy | Value                                                 |
| -------------- | -------------- | ------------------------------- | -------------- | ----------------------------------------------------- |
| Cookiebot      | Foreign cookie | `CookieConsent`                 | Contains       | `preferences:true`                                    |
| Borlabs Cookie | Foreign cookie | `borlabs-cookie`                | JSON path      | e.g. `consents.comfort`                               |
| CCM19          | Foreign cookie | Your shop's embedding ID cookie | Contains       | Identifier of the accepted group                      |
| Usercentrics   | Custom         | —                               | —              | see [Custom (JavaScript API)](#custom-javascript-api) |

Notes:

* **Cookiebot** writes a value that *looks* like JSON but is not. Use **Contains**, not the JSON path.
* **Borlabs Cookie** places the group identifier in the path, and it depends on the naming in your shop. Open the cookie in your browser once and read off the actual path.
* **Usercentrics** keeps consent in its JavaScript API rather than in a reliably readable cookie. Here the **Custom** source is the only dependable route.

### When Nothing Appears

The comparison deliberately fails **silently** — there is no message in the browser console. Any misconfiguration (empty cookie name, empty comparison value, unparsable JSON, a path that leads nowhere) results in "not granted". The symptom is unambiguous: the guest wishlist does not appear. In that case, check the cookie name, strategy and comparison value against the actual cookie content in your browser.

If the configured cookie does not exist at all, the plugin does **not** treat that as a refusal — a consent tool that is still loading simply has not written its cookie yet.

***

## Custom (JavaScript API)

If your consent tool cannot be read from a cookie, connect it through a small JavaScript interface. The plugin deliberately ships **no** tool-specific adapters — it only provides the connection point; the few lines of glue code live in your theme.

> This section is aimed at developers or your agency. A custom theme or plugin is required for the integration.

### The Bridge Block

The plugin provides an empty, overridable Twig block. Create an extension of `storefront/base.html.twig` in your theme:

```twig
{% sw_extends '@Storefront/storefront/base.html.twig' %}

{% block momo_guest_wishlist_consent_bridge %}
    <script>
        (function () {
            // Register the resolver first: it works regardless of whether
            // your consent tool has loaded by this point.
            window.MomoWishlistConsent.registerResolver(function () {
                if (!window.myCmp || !window.myCmp.isReady()) {
                    return null; // no statement possible yet
                }

                return window.myCmp.hasConsent('comfort');
            });

            // Event binding, as soon as the consent tool is available.
            // Safe to call repeatedly — it binds at most once.
            let bound = false;

            function bindMyCmp() {
                if (bound || !window.myCmp || typeof window.myCmp.onConsentChange !== 'function') {
                    return bound;
                }

                bound = true;

                window.myCmp.onConsentChange(function (consents) {
                    window.MomoWishlistConsent.set(consents.comfort === true);
                });

                // The tool is ready now — re-evaluate the state once
                window.MomoWishlistConsent.refresh();

                return true;
            }

            // If your consent tool loads asynchronously it is not here yet.
            // Bind on its own readiness signal — replace "myCmpReady" with the
            // event or callback your tool actually provides. The load event is
            // only a fallback: a tool that initialises after "load" would never
            // be caught by it.
            if (!bindMyCmp()) {
                document.addEventListener('myCmpReady', bindMyCmp);
                window.addEventListener('load', bindMyCmp);
            }
        }());
    </script>
{% endblock %}
```

Example for Usercentrics:

```twig
{% block momo_guest_wishlist_consent_bridge %}
    <script>
        window.addEventListener('ucEvent', function (event) {
            if (!event.detail || typeof event.detail !== 'object') {
                return;
            }

            // Use the service name from your Usercentrics admin
            window.MomoWishlistConsent.set(event.detail['Momo Advanced Wishlists'] === true);
        });
    </script>
{% endblock %}
```

Ready-made blocks for Cookiebot and Borlabs Cookie are available in the plugin's `README.md`.

### The `window.MomoWishlistConsent` Interface

| Method                 | Behaviour                                                                                                                                                                                                      |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `set(granted)`         | Grants or withdraws consent. No change is announced when the state is already the one you set. `set(false)` still deletes the cookie and the stored wishlist on every call, so it remains a reliable hard cut. |
| `isGranted()`          | Returns the currently resolved consent state.                                                                                                                                                                  |
| `onChange(callback)`   | Registers a listener and returns an unsubscribe function.                                                                                                                                                      |
| `registerResolver(fn)` | Registers a resolver that may return `true`, `false` or `null` (no opinion).                                                                                                                                   |
| `refresh()`            | Forces an immediate re-evaluation of all resolvers.                                                                                                                                                            |

The interface is available from the very first moment in the `<head>` — even very early calls from a consent tool are not lost; they are queued and applied once the theme has loaded.

**Evaluation order:** if *any* resolver returns `true`, consent counts as granted. Otherwise, if *any* resolver returns `false`, it counts as refused. If all abstain, the plugin's own consent cookie decides. A `true` deliberately beats every `false` — a resolver returning `true` has positively observed consent, whereas `false` often only means it could not confirm any yet. This implies a rule for your glue code: after a withdrawal, no resolver may keep returning `true`. The consequence depends on how the withdrawal reaches the plugin:

* **Through `set(false)`** — the consent cookie and the stored guest wishlist are deleted first, but the re-evaluation that follows sees the stale `true` and immediately grants consent again. The withdrawal does not stick: no change is announced, and the visitor can save new items right away.
* **Through a re-evaluation only** (Shopware's cookie banner, a returning browser tab) — the stale `true` means no change is detected at all, so no cleanup runs and the stored data stays.

Return `false` for an explicit refusal — or when the consent state you read is present but does not say yes. Return `null` when you have no opinion: your consent tool has not finished loading, or the value you would read has not been written yet. This is the same contract the built-in cookie evaluation of the **Foreign cookie** source follows, and the reason a missing cookie is an abstention rather than a refusal.

The cookie name, lifetime and active consent source are exposed to your glue code as data attributes on the `[data-momo-guest-wishlist-storage]` element. Read the values from there instead of hard-coding them.

***

## No Consent Check

With this source, the guest wishlist is active without any check. This makes sense if your consent handling happens entirely outside Shopware and you control the feature elsewhere.

Note that **no check means "no gate", not "consent granted"**. There is no consent state that could be withdrawn — `set(false)` has no effect in this source. Never test your glue code with this setting; test it with the source you intend to run in production.

***

## Behaviour Without Consent

When no consent is present, the **Wishlist control without guest consent** field in the **Storefront Appearance** section determines what the visitor sees. Unlike the consent source, this setting is configurable **per sales channel**.

* **Hide the control** *(default)* — The wishlist icon or button is not rendered at all. Existing installations behave exactly as before after an update.
* **Show the control and ask for consent** — The control stays visible but inactive. When the visitor clicks it, Shopware's cookie settings dialog opens. If that dialog is unavailable (for example because you use an external consent tool), a dismissible hint appears instead, explaining that consent is required for the wishlist.

**No product is ever saved while consent is missing.** The control never reports a successful save that did not happen. Items clicked before consent was granted are not added retroactively either — the visitor simply clicks again.

The hint text follows your selected [terminology preset](https://github.com/momocode-de/plugin-gitbook/tree/en/shopware-6/advanced-wishlists/configuration.md#terminology-preset) and can be customised under **Settings → Snippets** via the key `momoAdvancedWishlists.storefront.consent.requiredHint`.

The setting has no effect when the guest wishlist is disabled, when the consent source is set to **No consent check**, or when the product card button position is set to **No button**.

***

## Withdrawing Consent

When a visitor withdraws consent, the plugin immediately deletes:

* the plugin's own consent cookie
* the guest wishlist stored in the browser (`localStorage`)

The guest wishlist is empty afterwards and the header counter updates without a page reload. This applies equally to a withdrawal made through Shopware's cookie banner and one made through the JavaScript interface.

**Changing the consent source, by contrast, never deletes data.** If you switch from **Shopware cookie banner** to **Foreign cookie**, for example, visitors holding a still-valid plugin cookie remain enabled — that cookie continues to serve as a fallback. If you want a hard cut, call `window.MomoWishlistConsent.set(false)` once in the bridge block.

***

## When Consent Is Evaluated

The plugin does **not** poll for the consent state. It is evaluated:

* on page load
* when Shopware's cookie banner saves a changed selection
* when the visitor returns to the browser tab
* on an explicit `refresh()` from your glue code

As a result, changes take effect immediately and without a page reload — the wishlist control appears or disappears right away.
