From d6073c7888ea6009cb279730809fdb0e1d952c8f Mon Sep 17 00:00:00 2001 From: umut Date: Thu, 8 Oct 2026 15:24:08 +0200 Subject: [PATCH 1/5] docs: document server-side cookie consent logging --- .../content/cookie-consent-management.md | 28 ++- .../shopware/cookie-consent-logging.md | 197 ++++++++++++++++++ 2 files changed, 219 insertions(+), 6 deletions(-) create mode 100644 guides/hosting/configurations/shopware/cookie-consent-logging.md diff --git a/concepts/commerce/content/cookie-consent-management.md b/concepts/commerce/content/cookie-consent-management.md index a030236ece..dd5769eb5d 100644 --- a/concepts/commerce/content/cookie-consent-management.md +++ b/concepts/commerce/content/cookie-consent-management.md @@ -38,7 +38,7 @@ sequenceDiagram participant CookieProvider User->>Storefront: Visit shop - Storefront->>StoreAPI: GET /store-api/cookie/groups + Storefront->>StoreAPI: GET /store-api/cookie-groups StoreAPI->>CookieProvider: getCookieGroups() CookieProvider-->>StoreAPI: Cookie groups + hash StoreAPI-->>Storefront: Cookie configuration @@ -154,10 +154,11 @@ Multiple related cookies grouped together for easier management. The cookie consent system itself uses special cookies: -| Cookie | Purpose | Lifetime | -| -------------------- | ----------------------------------------- | -------- | -| `cookie-preference` | Stores user's consent choices | 30 days | -| `cookie-config-hash` | Tracks configuration changes per language | 30 days | +| Cookie | Purpose | Lifetime | +| -------------------- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | +| `cookie-preference` | Stores user's consent choices | 30 days | +| `cookie-config-hash` | Tracks configuration changes per language | 30 days | +| `cookie-consent-id` | Links the consent decisions of this browser in the server-side consent log. Only set while consent logging is on | Retention period of the log, 120 days by default | ### Protected Cookies @@ -183,12 +184,26 @@ The Store API endpoint for cookie groups is available starting with Shopware 6.7 The cookie consent system exposes its configuration through the Store API endpoint: -**Endpoint:** `GET /store-api/cookie/groups` +**Endpoint:** `GET /store-api/cookie-groups` This endpoint enables headless implementations, custom frontends, and third-party integrations to retrieve cookie configuration, the configuration hash, and the language ID. The hash is provided as a string, and the language ID is also returned by the endpoint. When stored in the browser's `cookie-config-hash` cookie, both values should be stored as an object where the language ID is the key and the hash is the value, for example: `{"019ada128cfb711aa7a0d00f476d5961":"998cdcc090e92b3ecdd057241d0fd01f"}` +Every cookie group has a `technicalName`, such as `cookie.groupStatistical`. Unlike `name`, it is the same in every language. + For full API documentation, see the [Store API - Fetch all cookie groups](https://shopware.stoplight.io/docs/store-api/f9c70be044a15-fetch-all-cookie-groups) reference. +## Server-Side Consent Logging + +::: info +Server-side consent logging is available starting with Shopware 6.7.16.0. +::: + +The cookie banner can record every consent decision on the server. Logging is off by default. When it is on, the storefront sends each decision to the server in the background. The server stores the decision together with a snapshot of the banner that the visitor saw. + +A record contains a random consent ID, but no IP address, session or customer. Shops can store the log in the database, on the filesystem or in a custom storage. + + + ## Extension Points The cookie consent system can be extended in multiple ways: @@ -269,6 +284,7 @@ Shopware's cookie consent system includes several features designed to help shop - ✅ **Easy withdrawal** - Users can change preferences at any time - ✅ **Configuration tracking** - Hash mechanism ensures change detection - ✅ **Documented lifecycle** - Full audit trail of cookie changes +- ✅ **Consent log** - Optional server-side record of every consent decision ::: info These features provide technical support for GDPR compliance, but shop owners must also ensure they have proper legal documentation (privacy policy, terms of service), data processing agreements, and regular compliance audits. Consult with legal counsel to ensure full compliance with GDPR and other applicable regulations. diff --git a/guides/hosting/configurations/shopware/cookie-consent-logging.md b/guides/hosting/configurations/shopware/cookie-consent-logging.md new file mode 100644 index 0000000000..936bd9ceae --- /dev/null +++ b/guides/hosting/configurations/shopware/cookie-consent-logging.md @@ -0,0 +1,197 @@ +--- +nav: + title: Cookie consent logging + position: 60 + +--- + +# Cookie Consent Logging + +::: info +This feature is available since Shopware 6.7.16.0. +::: + +## Overview + +The built-in Shopware cookie banner can record every consent decision on the server, together with the banner that the visitor saw. Logging is off by default. + +::: warning +Shop owners are responsible for using the consent log in line with the GDPR and other applicable data protection regulations. +::: + +For the cookie banner itself, see [Cookie Consent Management](../../../../concepts/commerce/content/cookie-consent-management.md). + +## What is recorded + +The storefront sends every decision to the server in the background. This includes the cookie banner (accept all, only required, own selection) and the consent dialog of single features, such as the wishlist. The banner does not wait for this request. + +The browser only reports raw facts: a random consent ID, the action, and the names of the cookies that the visitor accepted. The server derives everything else from its own cookie configuration. + +| Field | Content | +| ----------------- | ----------------------------------------------------------------------------------------------------------------------- | +| `consentId` | Random token that the browser creates on the first decision and keeps in the `cookie-consent-id` cookie | +| `consentAction` | `accept_all`, `accept_required` or `accept_selected` | +| `groupDecisions` | Decision per cookie group, keyed by the technical name of the group: `accepted`, `partial` or `rejected` | +| `acceptedCookies` | Names of the accepted cookies that need consent. Names that the cookie configuration does not know are ignored | +| `configHash` | Hash of the banner configuration that the visitor saw | +| `salesChannelId` | Sales channel of the decision | +| `languageId` | Language of the banner that the visitor saw | +| `createdAt` | Time of the decision | + +Technically required groups are always `accepted`. Any other group is `accepted` only when the visitor accepted every cookie that they could select in it. A group without selectable cookies is `rejected`. + +### Banner snapshots + +Shopware stores the banner configuration once per configuration hash, as a snapshot. The snapshot contains the cookie groups with their texts, as the visitor saw them. The texts are part of the hash, so every language has its own snapshot. Every decision refers to its snapshot through `configHash`. + +Snapshots contain only the banner configuration, no visitor data. The cleanup task does not delete them. + +### Withdrawals + +A visitor can open the banner again and accept less. This writes a second record with the same consent ID and the narrower decision. All records of one consent ID show the history of the decisions of one browser. + +## Enable logging + +Select a storage in your `shopware.yaml`, for example in `config/packages/z-shopware.yaml`: + +```yaml +shopware: + cookie_consent: + # none (default), database, filesystem or the name of a custom storage + log_storage: database + # Days a recorded decision is kept, 120 by default + retention_days: 365 +``` + +Clear the cache after the change. + +While logging is on: + +- The storefront sets the cookie `cookie-consent-id`. The banner lists it as a technically required cookie. Its lifetime is `retention_days`, and every decision renews it. +- The banner configuration changes when you turn logging on or off. Visitors see the banner once more, so their decision gets logged. + +While logging is off, the storefront sends no request and sets no `cookie-consent-id` cookie. + +## Storages + +Select the storage that fits the traffic of your shop. The setting applies to the whole installation, not per sales channel. + +### Database + +The `database` storage writes to the tables `cookie_consent_log` and `cookie_consent_config_snapshot`. These tables exist in every shop and stay empty until you select this storage. + +Sales channel and language are stored as IDs, without foreign keys. The records stay when you delete a sales channel or a language. + +### Filesystem + +The `filesystem` storage writes one JSON file per decision to the private filesystem (`shopware.filesystem.private`), below `cookie-consent/`. The directories group the decisions by year, month, day and hour (UTC). The consent ID is part of the file name, so a file search finds all decisions of one visitor. The banner snapshots are in `cookie-consent/snapshots/`. + +Point the private filesystem to object storage, such as Amazon S3, to keep a high-volume log out of the shop database. + +### Custom storage + +A plugin can add its own storage. Implement `Shopware\Core\Content\Cookie\ConsentLog\CookieConsentLogStorageInterface`: + +```php + + + +``` + +Then select it by this name: + +```yaml +shopware: + cookie_consent: + log_storage: example +``` + +## Retention and cleanup + +The daily scheduled task `cookie_consent_log.cleanup` deletes the decisions that are older than `retention_days`. The `filesystem` storage deletes whole hour directories, so it is accurate to one hour. + +The retention period is a decision of the shop owner. + +::: warning +When you change the storage, the records in the previous storage are not moved. The cleanup task only runs on the selected storage, so delete the old records yourself. +::: + +## Rate limiting + +The consent log routes are rate limited per client IP address. The limiter `cookie_consent_log` allows 60 requests per 60 seconds, as a sliding window. The IP address is only the key of the limiter. Shopware does not store it with the decision. + +Behind a CDN, a load balancer or a reverse proxy, configure the [trusted proxies](../../infrastructure/reverse-http-cache.md#trusted-proxies). Without it, all visitors get the IP address of the proxy and share one limit. Decisions over the limit are lost without a notice. + +To change the limit, override the limiter in your `shopware.yaml`: + +```yaml +shopware: + api: + rate_limiter: + cookie_consent_log: + enabled: true + policy: 'sliding_window' + limit: 120 + interval: '60 seconds' +``` + +## Export + +Export the log with this command. It writes JSON or CSV to standard output: + +```bash +bin/console cookie:consent:export --from=2026-01-01 --to=2026-07-01 --format=csv > consents.csv +``` + +| Option | Description | +| -------------------- | -------------------------------------------------------------------------- | +| `--from` | Decisions recorded at or after this date and time, `1970-01-01` by default | +| `--to` | Decisions recorded before this date and time, now by default | +| `--sales-channel-id` | Only decisions of this sales channel | +| `--format` | `json` (default) or `csv` | + +The command writes errors to standard error, so they do not end up in the exported file. + +The export contains the decisions. To show the banner that a visitor saw, find the snapshot with the `configHash` of the decision: in the table `cookie_consent_config_snapshot`, or in `cookie-consent/snapshots/.json`. + +## Extension events + +The Store API route publishes the extension `cookie-consent-log-route.log` with the payload, the request and the sales channel context. Plugins can react to it before and after a decision is logged. + + From d9d3c7ed11fb4711c88e9490fc0c2e1d170caa8e Mon Sep 17 00:00:00 2001 From: umut Date: Thu, 8 Oct 2026 15:27:53 +0200 Subject: [PATCH 2/5] docs: use the directory form for the extension points link --- .../hosting/configurations/shopware/cookie-consent-logging.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/hosting/configurations/shopware/cookie-consent-logging.md b/guides/hosting/configurations/shopware/cookie-consent-logging.md index 936bd9ceae..ab2daa9ae3 100644 --- a/guides/hosting/configurations/shopware/cookie-consent-logging.md +++ b/guides/hosting/configurations/shopware/cookie-consent-logging.md @@ -194,4 +194,4 @@ The export contains the decisions. To show the banner that a visitor saw, find t The Store API route publishes the extension `cookie-consent-log-route.log` with the payload, the request and the sales channel context. Plugins can react to it before and after a decision is logged. - + From db996e578e0b4d9556933d27efbd87c44af9102d Mon Sep 17 00:00:00 2001 From: umut Date: Thu, 29 Oct 2026 11:49:43 +0100 Subject: [PATCH 3/5] docs: explain the consent log endpoint for headless frontends --- .../hosting/configurations/shopware/cookie-consent-logging.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/hosting/configurations/shopware/cookie-consent-logging.md b/guides/hosting/configurations/shopware/cookie-consent-logging.md index ab2daa9ae3..32203182ff 100644 --- a/guides/hosting/configurations/shopware/cookie-consent-logging.md +++ b/guides/hosting/configurations/shopware/cookie-consent-logging.md @@ -70,7 +70,7 @@ While logging is on: - The storefront sets the cookie `cookie-consent-id`. The banner lists it as a technically required cookie. Its lifetime is `retention_days`, and every decision renews it. - The banner configuration changes when you turn logging on or off. Visitors see the banner once more, so their decision gets logged. -While logging is off, the storefront sends no request and sets no `cookie-consent-id` cookie. +While logging is off, the storefront sends no request and sets no `cookie-consent-id` cookie. `/store-api/cookie-groups` does not list this cookie then, so headless frontends can skip the request too. ## Storages From 90b29a2ac47a2d4f2d4757d744dae2af10f4624b Mon Sep 17 00:00:00 2001 From: umut Date: Thu, 29 Oct 2026 11:56:19 +0100 Subject: [PATCH 4/5] docs: explain the consent log endpoint for headless frontends --- concepts/commerce/content/cookie-consent-management.md | 2 +- .../hosting/configurations/shopware/cookie-consent-logging.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/concepts/commerce/content/cookie-consent-management.md b/concepts/commerce/content/cookie-consent-management.md index dd5769eb5d..f24e788572 100644 --- a/concepts/commerce/content/cookie-consent-management.md +++ b/concepts/commerce/content/cookie-consent-management.md @@ -195,7 +195,7 @@ For full API documentation, see the [Store API - Fetch all cookie groups](https: ## Server-Side Consent Logging ::: info -Server-side consent logging is available starting with Shopware 6.7.16.0. +Server-side consent logging is available starting with Shopware 6.7.17.0. ::: The cookie banner can record every consent decision on the server. Logging is off by default. When it is on, the storefront sends each decision to the server in the background. The server stores the decision together with a snapshot of the banner that the visitor saw. diff --git a/guides/hosting/configurations/shopware/cookie-consent-logging.md b/guides/hosting/configurations/shopware/cookie-consent-logging.md index 32203182ff..28e0a1b4a0 100644 --- a/guides/hosting/configurations/shopware/cookie-consent-logging.md +++ b/guides/hosting/configurations/shopware/cookie-consent-logging.md @@ -8,7 +8,7 @@ nav: # Cookie Consent Logging ::: info -This feature is available since Shopware 6.7.16.0. +This feature is available since Shopware 6.7.17.0. ::: ## Overview From e6b07052102752be933cdece14692812fc18a26a Mon Sep 17 00:00:00 2001 From: umut Date: Tue, 3 Nov 2026 09:33:05 +0100 Subject: [PATCH 5/5] docs: cookie consent cleanup runs on every storage --- .../hosting/configurations/shopware/cookie-consent-logging.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/guides/hosting/configurations/shopware/cookie-consent-logging.md b/guides/hosting/configurations/shopware/cookie-consent-logging.md index 28e0a1b4a0..7f1a8e4c46 100644 --- a/guides/hosting/configurations/shopware/cookie-consent-logging.md +++ b/guides/hosting/configurations/shopware/cookie-consent-logging.md @@ -146,10 +146,12 @@ shopware: The daily scheduled task `cookie_consent_log.cleanup` deletes the decisions that are older than `retention_days`. The `filesystem` storage deletes whole hour directories, so it is accurate to one hour. +The task cleans every storage, not only the one that is selected. So the retention still applies to the records in a storage that you switched away from, including after you set `log_storage` back to `none`. + The retention period is a decision of the shop owner. ::: warning -When you change the storage, the records in the previous storage are not moved. The cleanup task only runs on the selected storage, so delete the old records yourself. +When you change the storage, the existing records are not moved to the new storage. Each storage keeps its own records, and the cleanup task deletes them after the retention period. ::: ## Rate limiting