From 9029ca279790b0ade26462504f257971324b0f2f Mon Sep 17 00:00:00 2001 From: BrocksiNet Date: Wed, 14 Oct 2026 11:45:09 +0200 Subject: [PATCH 01/10] docs: add a guide for Storefront analytics with Google Analytics 4 --- .../plugins/storefront/advanced/index.md | 3 +- .../advanced/storefront-analytics.md | 229 ++++++++++++++++++ 2 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 guides/plugins/plugins/storefront/advanced/storefront-analytics.md diff --git a/guides/plugins/plugins/storefront/advanced/index.md b/guides/plugins/plugins/storefront/advanced/index.md index 2bacd1c08b..10ba9be4d7 100644 --- a/guides/plugins/plugins/storefront/advanced/index.md +++ b/guides/plugins/plugins/storefront/advanced/index.md @@ -8,9 +8,10 @@ nav: This section covers advanced topics for extending and customizing the Storefront in plugins. -These guides focus on performance optimization, caching behavior, cookie consent integration, and JavaScript plugin control: +These guides focus on performance optimization, caching behavior, cookie consent integration, analytics, and JavaScript plugin control: * [Add caching to custom controller](./add-caching-to-custom-controller.md) * [Add cookie to manager](./add-cookie-to-manager.md) * [Reacting to cookie consent changes](./reacting-to-cookie-consent-changes.md) * [Remove JavaScript plugin](./remove-unnecessary-js-plugin.md) +* [Storefront analytics with Google Analytics 4](./storefront-analytics.md) diff --git a/guides/plugins/plugins/storefront/advanced/storefront-analytics.md b/guides/plugins/plugins/storefront/advanced/storefront-analytics.md new file mode 100644 index 0000000000..4ec8906166 --- /dev/null +++ b/guides/plugins/plugins/storefront/advanced/storefront-analytics.md @@ -0,0 +1,229 @@ +--- +nav: + title: Storefront analytics with Google Analytics 4 + position: 180 + +--- + +# Storefront analytics with Google Analytics 4 + +The Storefront reports ecommerce events to Google Analytics 4 (GA4) when analytics are active for a sales channel. This guide describes the data the Storefront sends, the identifiers your Google Tag Manager setup can rely on, and how an extension makes its own products and lists visible to analytics. + +::: info +This guide describes the behavior of Shopware 6.7.16.0 and later. Earlier versions send a different payload. The release notes of 6.7.16.0 list what changed. +::: + +## Prerequisites + +Analytics are configured per sales channel in the Administration, in the analytics settings of the sales channel. The Storefront only loads the analytics script when a tracking ID is set and analytics are active. With the default cookie consent, the script only starts after the shopper accepted the Google Analytics or Google Ads cookie. + +A sales channel without active analytics renders none of the analytics attributes described in this guide, loads no analytics script, and answers the analytics routes with a 404. + +## Delivery + +The Storefront chooses the transport by the tracking ID: + +* A Google tag ID, such as `G-XXXXXXX`, sends every event with `gtag('event', name, parameters)`. +* A Google Tag Manager ID, such as `GTM-XXXXXXX`, pushes ecommerce events to `window.dataLayer` in the format Google documents for GA4. The previous ecommerce object is cleared first. + +```javascript +window.dataLayer.push({ ecommerce: null }); +window.dataLayer.push({ + event: 'add_to_cart', + ecommerce: { + currency: 'EUR', + value: 39.98, + items: [{ item_id: 'SW10001', item_name: 'Shirt', price: 19.99, quantity: 2 }], + }, +}); +``` + +Events without ecommerce data, such as `login`, `sign_up` and `search`, are pushed with their parameters at the top level, for example `{ event: 'login', method: 'mail' }`. + +In Google Tag Manager, read the parameters with data layer variables such as `ecommerce.items` or `ecommerce.value`, and use the GA4 event tag with "Send Ecommerce data" enabled. + +## Events + +| Event | Reported when | +| ---------------------------- | ----------------------------------------------------------------------------------------------------------- | +| `view_item_list` | A product listing is shown, filtered, sorted or paginated | +| `select_item` | The shopper follows a product link in a list | +| `view_item` | A product detail page is shown | +| `add_to_cart` | A product is added to the cart | +| `remove_from_cart` | A product is removed from the cart | +| `add_to_wishlist` | A product is added to the wishlist | +| `remove_from_wishlist` | A product is removed from the wishlist | +| `view_cart` | The cart page is shown, or the off-canvas cart opens when its tracking is enabled in the analytics settings | +| `begin_checkout` | The shopper starts the checkout | +| `add_shipping_info` | A shipping method is selected, once per method and checkout | +| `add_payment_info` | A payment method is selected, once per method and checkout | +| `purchase` | An order is placed | +| `login`, `sign_up`, `search` | The shopper logs in, registers or searches | + +## Event and item parameters + +Items use the GA4 property names, and all numeric values are numbers: + +| Parameter | Content | +| ----------------------------------------- | -------------------------------------------------------------- | +| `item_id` | The product number, or the product ID without a product number | +| `item_name` | The translated product name | +| `item_brand` | The translated manufacturer name | +| `item_variant` | The selected options of a variant, for example `Red, L` | +| `item_category` to `item_category5` | The category path of the product, at most five levels | +| `price` | The unit price before discounts | +| `quantity` | The quantity of the line item | +| `item_list_id`, `item_list_name`, `index` | The list the product was presented in, see [Lists](#lists) | + +The cart, checkout and `purchase` events report these event parameters: + +* `value` is the position price: all line items including promotion discounts, without shipping. +* `coupon` holds the codes of the applied promotions, separated by a comma. +* `shipping` and `tax` of `purchase` are reported separately from `value`. +* Discounts and other line items that are not products are not reported as items. + +`add_to_cart` reports the unit price of the graduated price that applies to the quantity the cart holds after the add, and the value of the added quantity. + +### Categories + +On a category page, the categories come from the breadcrumb. On pages whose breadcrumb does not describe the product, such as the homepage, a landing page, the wishlist, or a cross selling product on a product detail page, the analytics script requests the path of the product when the shopper adds or removes it. The route `frontend.analytics.product-categories` answers `GET /widgets/analytics/product-categories?productId=` with the breadcrumb of the product detail page as a list of names. It is HTTP cached, and its URL is only added to `window.router` when analytics are active. + +Products added from a product box post their brand and categories in the line item payload, as `manufacturerName` and `categoryNames`. The cart, checkout and purchase events read them from there, so neither the cart nor the checkout loads anything for analytics. + +## Lists + +`view_item_list` and `select_item` report the list a product was presented in as `item_list_id` and `item_list_name`, and its position as `index`. The index counts from zero across the pages of a paginated listing. `view_item` repeats the list the product was selected from on its item, also when the shopper opened the product in another tab. + +The list IDs are a contract that Google Tag Manager triggers can rely on: + +| List | `item_list_id` | `item_list_name` | +| -------------------------------------- | ---------------------------------- | ----------------------------------------------- | +| Category listing | `category:` | Translated category name | +| Listing outside a category | `cms:` | None | +| Search results | `search` | Translated snippet `search.analyticsListName` | +| Wishlist | `wishlist` | Translated snippet `wishlist.analyticsListName` | +| Cross selling tab | `cross_selling:` | Translated name of the cross selling group | +| Product slider | `slider:` | Title of the slider | +| Any other Shopping Experiences element | `cms:` | None | + +The list of a selected product is kept in the local storage of the browser under `swGaSelectedItemLists` for 30 minutes and is removed by the first view of the product. + +## Make extension markup visible to analytics + +### Products + +Analytics treat every element with a `data-product-information` attribute as a product, not only the `.product-box` of the default theme. The attribute holds a JSON object with at least the product `id`: + +```twig +{% set productInformation = { + id: product.id, + sku: product.productNumber, + name: product.translated.name, + brand: product.manufacturer.translated.name|default(''), + price: product.calculatedPrice.unitPrice +} %} + + +``` + +| Property | Required | Reported as | +| --------- | -------- | --------------------------------------------------------- | +| `id` | Yes | Used to match the product, and as `item_id` without `sku` | +| `sku` | No | `item_id` | +| `name` | No | `item_name` | +| `brand` | No | `item_brand` | +| `price` | No | `price` | +| `variant` | No | `item_variant` | + +Only these properties are reported. Other keys of the object are ignored, so the attribute can carry data for your own scripts. + +A link inside the element reports `select_item`. Buttons and forms inside the element, such as the buy button, are not reported as a selection. + +### Lists + +A product element inside a Shopping Experiences element is attributed to that element as `cms:` without any change. To report your own list ID and name, set `data-list-id` and `data-list-name` on an element that contains the product elements: + +```twig +{% set analyticsActive = storefrontAnalytics and storefrontAnalytics.isActive() %} + +
+ {# product elements #} +
+``` + +Prefix your list IDs with the name of your extension, so they cannot collide with the IDs of Shopware or other extensions. + +A list that is paginated can set `data-list-start` on itself or on an element inside it, with the position of its first product. The index then continues across pages. + +A theme that renders `@Storefront/storefront/component/product/listing.html.twig` can pass the list through the `listId` and `listName` variables instead. + +::: warning +Render analytics attributes only when `storefrontAnalytics and storefrontAnalytics.isActive()` is true, as Shopware does. A sales channel without analytics must not carry analytics data in its HTML. +::: + +## Checkout steps + +The shipping and payment method forms of the confirm page reload the page on every change. `add_shipping_info` and `add_payment_info` are therefore reported once per selected method of a checkout. A reload that keeps the method reports nothing, and selecting another method reports it. The reported steps are kept in the session storage under `swGaReportedCheckoutSteps` and are cleared by `begin_checkout` and `purchase`. + +A new customer reports `add_shipping_info` with the shipping method of the context when submitting the registration on the checkout register page. + +## Custom events + +To report your own events, extend `AnalyticsEvent` from `src/plugin/google-analytics/analytics-event` and call `pushEvent()`. It chooses the transport of the sales channel and normalizes the item parameters. Pass `{ ecommerce: false }` as the third argument for an event without ecommerce data. + +```javascript +import AnalyticsEvent from 'src/plugin/google-analytics/analytics-event'; + +export default class GenerateLeadEvent extends AnalyticsEvent { + supports() { + return true; + } + + execute() { + document.addEventListener('submit', (event) => { + if (!this.active || !event.target.matches('.my-lead-form')) { + return; + } + + this.pushEvent('generate_lead', { currency: 'EUR', value: 50 }); + }); + } +} +``` + +Register the event by overriding the `GoogleAnalytics` plugin. The plugin is only registered when analytics are active, so the override does nothing in other sales channels: + +```javascript +// /src/Resources/app/storefront/src/my-google-analytics.plugin.js +import GoogleAnalyticsPlugin from 'src/plugin/google-analytics/google-analytics.plugin'; +import GenerateLeadEvent from './generate-lead.event'; + +export default class MyGoogleAnalyticsPlugin extends GoogleAnalyticsPlugin { + registerDefaultEvents() { + super.registerDefaultEvents(); + + this.registerEvent(GenerateLeadEvent); + } +} +``` + +```javascript +// /src/Resources/app/storefront/src/main.js +if (window.gtagActive) { + window.PluginManager.override('GoogleAnalytics', () => import('./my-google-analytics.plugin')); +} +``` + +The guide [Override existing JavaScript](../javascript/override-existing-javascript.md) explains plugin overrides in detail. + +## More information + +* [Google Analytics 4 ecommerce events](https://developers.google.com/analytics/devguides/collection/ga4/ecommerce) +* [Cookie consent management](../../../../../concepts/commerce/content/cookie-consent-management.md) +* [Reacting to cookie consent changes](./reacting-to-cookie-consent-changes.md) From 6648253d997b7f718fb81fd98f553e8547da2654 Mon Sep 17 00:00:00 2001 From: BrocksiNet Date: Wed, 14 Oct 2026 20:11:03 +0200 Subject: [PATCH 02/10] docs: describe the categories kept for the cart and checkout events --- .../plugins/plugins/storefront/advanced/storefront-analytics.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/guides/plugins/plugins/storefront/advanced/storefront-analytics.md b/guides/plugins/plugins/storefront/advanced/storefront-analytics.md index 4ec8906166..27f1489824 100644 --- a/guides/plugins/plugins/storefront/advanced/storefront-analytics.md +++ b/guides/plugins/plugins/storefront/advanced/storefront-analytics.md @@ -90,6 +90,8 @@ On a category page, the categories come from the breadcrumb. On pages whose brea Products added from a product box post their brand and categories in the line item payload, as `manufacturerName` and `categoryNames`. The cart, checkout and purchase events read them from there, so neither the cart nor the checkout loads anything for analytics. +A product added on a page without a breadcrumb about it has no categories in its payload. The browser keeps the categories requested for it in the local storage under `swGaProductCategories` for 30 days, and the cart, checkout and purchase events fill missing categories from there. The order removes them. A line item added in another browser or through the API is reported without categories. + ## Lists `view_item_list` and `select_item` report the list a product was presented in as `item_list_id` and `item_list_name`, and its position as `index`. The index counts from zero across the pages of a paginated listing. `view_item` repeats the list the product was selected from on its item, also when the shopper opened the product in another tab. From 3c84a8328d195ab626c90a546048a78ef603e8be Mon Sep 17 00:00:00 2001 From: BrocksiNet Date: Thu, 15 Oct 2026 11:53:45 +0200 Subject: [PATCH 03/10] docs: use the breadcrumb categories only for the listing and the detail product --- .../plugins/plugins/storefront/advanced/storefront-analytics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/plugins/plugins/storefront/advanced/storefront-analytics.md b/guides/plugins/plugins/storefront/advanced/storefront-analytics.md index 27f1489824..1a8b9919b4 100644 --- a/guides/plugins/plugins/storefront/advanced/storefront-analytics.md +++ b/guides/plugins/plugins/storefront/advanced/storefront-analytics.md @@ -86,7 +86,7 @@ The cart, checkout and `purchase` events report these event parameters: ### Categories -On a category page, the categories come from the breadcrumb. On pages whose breadcrumb does not describe the product, such as the homepage, a landing page, the wishlist, or a cross selling product on a product detail page, the analytics script requests the path of the product when the shopper adds or removes it. The route `frontend.analytics.product-categories` answers `GET /widgets/analytics/product-categories?productId=` with the breadcrumb of the product detail page as a list of names. It is HTTP cached, and its URL is only added to `window.router` when analytics are active. +On a category page, the products of the category listing take their categories from the breadcrumb. On a product detail page, the main product does. For every other product, such as on the homepage, a landing page or the wishlist, in a product slider of a category page, or in the cross selling of a product detail page, the analytics script requests the path of the product when the shopper adds or removes it. The route `frontend.analytics.product-categories` answers `GET /widgets/analytics/product-categories?productId=` with the breadcrumb of the product detail page as a list of names. It is HTTP cached, and its URL is only added to `window.router` when analytics are active. Products added from a product box post their brand and categories in the line item payload, as `manufacturerName` and `categoryNames`. The cart, checkout and purchase events read them from there, so neither the cart nor the checkout loads anything for analytics. From 2ae3e641eca09ea246705e3c79cb2540f962ff47 Mon Sep 17 00:00:00 2001 From: BrocksiNet Date: Thu, 15 Oct 2026 15:52:22 +0200 Subject: [PATCH 04/10] docs: describe when login, sign_up and the reorder are reported, and the rule price of products --- .../advanced/storefront-analytics.md | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/guides/plugins/plugins/storefront/advanced/storefront-analytics.md b/guides/plugins/plugins/storefront/advanced/storefront-analytics.md index 1a8b9919b4..14d7cf2ae2 100644 --- a/guides/plugins/plugins/storefront/advanced/storefront-analytics.md +++ b/guides/plugins/plugins/storefront/advanced/storefront-analytics.md @@ -44,21 +44,23 @@ In Google Tag Manager, read the parameters with data layer variables such as `ec ## Events -| Event | Reported when | -| ---------------------------- | ----------------------------------------------------------------------------------------------------------- | -| `view_item_list` | A product listing is shown, filtered, sorted or paginated | -| `select_item` | The shopper follows a product link in a list | -| `view_item` | A product detail page is shown | -| `add_to_cart` | A product is added to the cart | -| `remove_from_cart` | A product is removed from the cart | -| `add_to_wishlist` | A product is added to the wishlist | -| `remove_from_wishlist` | A product is removed from the wishlist | -| `view_cart` | The cart page is shown, or the off-canvas cart opens when its tracking is enabled in the analytics settings | -| `begin_checkout` | The shopper starts the checkout | -| `add_shipping_info` | A shipping method is selected, once per method and checkout | -| `add_payment_info` | A payment method is selected, once per method and checkout | -| `purchase` | An order is placed | -| `login`, `sign_up`, `search` | The shopper logs in, registers or searches | +| Event | Reported when | +| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| `view_item_list` | A product listing is shown, filtered, sorted or paginated | +| `select_item` | The shopper follows a product link in a list | +| `view_item` | A product detail page is shown | +| `add_to_cart` | A product is added to the cart. Repeating an order in the account reports one event with all its line items | +| `remove_from_cart` | A product is removed from the cart | +| `add_to_wishlist` | A product is added to the wishlist | +| `remove_from_wishlist` | A product is removed from the wishlist | +| `view_cart` | The cart page is shown, or the off-canvas cart opens when its tracking is enabled in the analytics settings | +| `begin_checkout` | The shopper starts the checkout | +| `add_shipping_info` | A shipping method is selected, once per method and checkout | +| `add_payment_info` | A payment method is selected, once per method and checkout | +| `purchase` | An order is placed | +| `login` | A login succeeded. Reported on the page after the login, so a wrong password reports nothing | +| `sign_up` | A customer account was created. Reported on the page after the registration. A guest checkout and a failed registration report nothing | +| `search` | The shopper searches | ## Event and item parameters @@ -117,12 +119,17 @@ The list of a selected product is kept in the local storage of the browser under Analytics treat every element with a `data-product-information` attribute as a product, not only the `.product-box` of the default theme. The attribute holds a JSON object with at least the product `id`: ```twig +{# a matching price rule or graduated prices replace the default price #} +{% set price = product.calculatedPrices.count > 0 + ? product.calculatedPrices.first.unitPrice + : product.calculatedPrice.unitPrice %} + {% set productInformation = { id: product.id, sku: product.productNumber, name: product.translated.name, brand: product.manufacturer.translated.name|default(''), - price: product.calculatedPrice.unitPrice + price: price } %}
@@ -139,6 +146,8 @@ Analytics treat every element with a `data-product-information` attribute as a p | `price` | No | `price` | | `variant` | No | `item_variant` | +Report the price the shopper pays for one piece, as in the example: `calculatedPrices.first` when a price rule or graduated prices apply, otherwise `calculatedPrice`. The product box and the product detail page do the same. + Only these properties are reported. Other keys of the object are ignored, so the attribute can carry data for your own scripts. A link inside the element reports `select_item`. Buttons and forms inside the element, such as the buy button, are not reported as a selection. From 001e555984a2d2a1ab9b0d7cbfaf587b9279cf0d Mon Sep 17 00:00:00 2001 From: BrocksiNet Date: Mon, 19 Oct 2026 09:00:51 +0200 Subject: [PATCH 05/10] docs: report the search term of the search results and the sign-up of a converted guest in GA4 --- .../plugins/storefront/advanced/storefront-analytics.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/guides/plugins/plugins/storefront/advanced/storefront-analytics.md b/guides/plugins/plugins/storefront/advanced/storefront-analytics.md index 14d7cf2ae2..824cf40388 100644 --- a/guides/plugins/plugins/storefront/advanced/storefront-analytics.md +++ b/guides/plugins/plugins/storefront/advanced/storefront-analytics.md @@ -59,7 +59,7 @@ In Google Tag Manager, read the parameters with data layer variables such as `ec | `add_payment_info` | A payment method is selected, once per method and checkout | | `purchase` | An order is placed | | `login` | A login succeeded. Reported on the page after the login, so a wrong password reports nothing | -| `sign_up` | A customer account was created. Reported on the page after the registration. A guest checkout and a failed registration report nothing | +| `sign_up` | A customer account was created, also by a guest with "Create account" on the checkout finish page. Reported on the page after the registration. A guest checkout and a failed registration report nothing | | `search` | The shopper searches | ## Event and item parameters @@ -110,6 +110,8 @@ The list IDs are a contract that Google Tag Manager triggers can rely on: | Product slider | `slider:` | Title of the slider | | Any other Shopping Experiences element | `cms:` | None | +For the search results, `view_item_list` and `select_item` also report the query as `search_term`, and `view_item` repeats it for a product selected from the search results. GA4 needs an event-scoped custom dimension for `search_term` to show it in reports of these events. + The list of a selected product is kept in the local storage of the browser under `swGaSelectedItemLists` for 30 minutes and is removed by the first view of the product. ## Make extension markup visible to analytics From 2ec1a33604dafc6e1c57658c1256457213867fbd Mon Sep 17 00:00:00 2001 From: BrocksiNet Date: Tue, 20 Oct 2026 10:15:06 +0200 Subject: [PATCH 06/10] docs: target Shopware 6.7.17.0 in the storefront analytics guide --- .../plugins/plugins/storefront/advanced/storefront-analytics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/plugins/plugins/storefront/advanced/storefront-analytics.md b/guides/plugins/plugins/storefront/advanced/storefront-analytics.md index 824cf40388..49a572ec8b 100644 --- a/guides/plugins/plugins/storefront/advanced/storefront-analytics.md +++ b/guides/plugins/plugins/storefront/advanced/storefront-analytics.md @@ -10,7 +10,7 @@ nav: The Storefront reports ecommerce events to Google Analytics 4 (GA4) when analytics are active for a sales channel. This guide describes the data the Storefront sends, the identifiers your Google Tag Manager setup can rely on, and how an extension makes its own products and lists visible to analytics. ::: info -This guide describes the behavior of Shopware 6.7.16.0 and later. Earlier versions send a different payload. The release notes of 6.7.16.0 list what changed. +This guide describes the behavior of Shopware 6.7.17.0 and later. Earlier versions send a different payload. The release notes of 6.7.17.0 list what changed. ::: ## Prerequisites From 38a19041a1a0ef5f109c5dfec27b94042214ea55 Mon Sep 17 00:00:00 2001 From: BrocksiNet Date: Thu, 29 Oct 2026 08:24:53 +0100 Subject: [PATCH 07/10] docs: align the analytics event table and describe the reorder, amount and category request behaviour --- .../advanced/storefront-analytics.md | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/guides/plugins/plugins/storefront/advanced/storefront-analytics.md b/guides/plugins/plugins/storefront/advanced/storefront-analytics.md index 49a572ec8b..7c8541c9aa 100644 --- a/guides/plugins/plugins/storefront/advanced/storefront-analytics.md +++ b/guides/plugins/plugins/storefront/advanced/storefront-analytics.md @@ -44,27 +44,28 @@ In Google Tag Manager, read the parameters with data layer variables such as `ec ## Events -| Event | Reported when | -| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | -| `view_item_list` | A product listing is shown, filtered, sorted or paginated | -| `select_item` | The shopper follows a product link in a list | -| `view_item` | A product detail page is shown | -| `add_to_cart` | A product is added to the cart. Repeating an order in the account reports one event with all its line items | -| `remove_from_cart` | A product is removed from the cart | -| `add_to_wishlist` | A product is added to the wishlist | -| `remove_from_wishlist` | A product is removed from the wishlist | -| `view_cart` | The cart page is shown, or the off-canvas cart opens when its tracking is enabled in the analytics settings | -| `begin_checkout` | The shopper starts the checkout | -| `add_shipping_info` | A shipping method is selected, once per method and checkout | -| `add_payment_info` | A payment method is selected, once per method and checkout | -| `purchase` | An order is placed | -| `login` | A login succeeded. Reported on the page after the login, so a wrong password reports nothing | +| Event | Reported when | +| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `view_item_list` | A product listing is shown, filtered, sorted or paginated | +| `select_item` | The shopper follows a product link in a list | +| `view_item` | A product detail page is shown | +| `add_to_cart` | A product is added to the cart. Repeating an order in the account reports one event with the products it added, priced with the current prices of the cart | +| `remove_from_cart` | A product is removed from the cart | +| `add_to_wishlist` | A product is added to the wishlist | +| `remove_from_wishlist` | A product is removed from the wishlist | +| `view_cart` | The cart page is shown, or the off-canvas cart opens when its tracking is enabled in the analytics settings | +| `begin_checkout` | The shopper starts the checkout | +| `add_shipping_info` | A shipping method is selected, once per method and checkout | +| `add_payment_info` | A payment method is selected, once per method and checkout | +| `purchase` | An order is placed | +| `login` | A login succeeded. Reported on the page after the login, so a wrong password reports nothing | | `sign_up` | A customer account was created, also by a guest with "Create account" on the checkout finish page. Reported on the page after the registration. A guest checkout and a failed registration report nothing | -| `search` | The shopper searches | +| `search` | The shopper searches | ## Event and item parameters -Items use the GA4 property names, and all numeric values are numbers: +Items use the GA4 property names, and all numeric values are numbers. +Amounts keep the decimals of the currency: | Parameter | Content | | ----------------------------------------- | -------------------------------------------------------------- | @@ -88,7 +89,7 @@ The cart, checkout and `purchase` events report these event parameters: ### Categories -On a category page, the products of the category listing take their categories from the breadcrumb. On a product detail page, the main product does. For every other product, such as on the homepage, a landing page or the wishlist, in a product slider of a category page, or in the cross selling of a product detail page, the analytics script requests the path of the product when the shopper adds or removes it. The route `frontend.analytics.product-categories` answers `GET /widgets/analytics/product-categories?productId=` with the breadcrumb of the product detail page as a list of names. It is HTTP cached, and its URL is only added to `window.router` when analytics are active. +On a category page, the products of the category listing take their categories from the breadcrumb. On a product detail page, the main product does. For every other product, such as on the homepage, a landing page or the wishlist, in a product slider of a category page, or in the cross selling of a product detail page, the analytics script requests the path of the product when the shopper adds or removes it. The route `frontend.analytics.product-categories` answers `GET /widgets/analytics/product-categories?productId=` with the breadcrumb of the product detail page as a list of names. It is HTTP cached, and its URL is only added to `window.router` when analytics are active. A request that takes longer than a second is aborted, and the event is reported without categories. Products added from a product box post their brand and categories in the line item payload, as `manufacturerName` and `categoryNames`. The cart, checkout and purchase events read them from there, so neither the cart nor the checkout loads anything for analytics. From 3615a626015bef4da889b26fb85a65cccf407c5c Mon Sep 17 00:00:00 2001 From: BrocksiNet Date: Thu, 29 Oct 2026 08:25:04 +0100 Subject: [PATCH 08/10] docs: split the item parameter introduction into two sentences --- .../plugins/storefront/advanced/storefront-analytics.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/guides/plugins/plugins/storefront/advanced/storefront-analytics.md b/guides/plugins/plugins/storefront/advanced/storefront-analytics.md index 7c8541c9aa..4ff32db7ad 100644 --- a/guides/plugins/plugins/storefront/advanced/storefront-analytics.md +++ b/guides/plugins/plugins/storefront/advanced/storefront-analytics.md @@ -64,8 +64,8 @@ In Google Tag Manager, read the parameters with data layer variables such as `ec ## Event and item parameters -Items use the GA4 property names, and all numeric values are numbers. -Amounts keep the decimals of the currency: +Items use the GA4 property names. +All numeric values are numbers, and amounts keep the decimals of the currency: | Parameter | Content | | ----------------------------------------- | -------------------------------------------------------------- | From 8f2277a94d90fa8d2ae5f596691729da095c8c8e Mon Sep 17 00:00:00 2001 From: BrocksiNet Date: Fri, 30 Oct 2026 10:11:05 +0100 Subject: [PATCH 09/10] docs: mark the generate_lead example as non-ecommerce and document the product box block --- .../storefront/advanced/storefront-analytics.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/guides/plugins/plugins/storefront/advanced/storefront-analytics.md b/guides/plugins/plugins/storefront/advanced/storefront-analytics.md index 4ff32db7ad..05c4adc758 100644 --- a/guides/plugins/plugins/storefront/advanced/storefront-analytics.md +++ b/guides/plugins/plugins/storefront/advanced/storefront-analytics.md @@ -153,6 +153,14 @@ Report the price the shopper pays for one piece, as in the example: `calculatedP Only these properties are reported. Other keys of the object are ignored, so the attribute can carry data for your own scripts. +The product box renders its attribute in the Twig block `component_product_box_product_information` of `storefront/component/product/card/box-standard.html.twig`. Override the block to add keys or change values: + +```twig +{% sw_extends '@Storefront/storefront/component/product/card/box-standard.html.twig' %} + +{% block component_product_box_product_information %}{{ productInformation|merge({ myKey: 'value' })|json_encode }}{% endblock %} +``` + A link inside the element reports `select_item`. Buttons and forms inside the element, such as the buy button, are not reported as a selection. ### Lists @@ -205,7 +213,7 @@ export default class GenerateLeadEvent extends AnalyticsEvent { return; } - this.pushEvent('generate_lead', { currency: 'EUR', value: 50 }); + this.pushEvent('generate_lead', { currency: 'EUR', value: 50 }, { ecommerce: false }); }); } } From c6a6c1523390df35b1df0a1761f13c4f98b8b11f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Nov 2026 09:15:08 +0000 Subject: [PATCH 10/10] Fix announcement detector comment permissions Co-authored-by: sushmangupta <112690947+sushmangupta@users.noreply.github.com> --- .github/workflows/announcement-detector.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/announcement-detector.yml b/.github/workflows/announcement-detector.yml index 279a6928d1..ced6819d9e 100644 --- a/.github/workflows/announcement-detector.yml +++ b/.github/workflows/announcement-detector.yml @@ -9,7 +9,7 @@ on: permissions: contents: read - pull-requests: read + pull-requests: write issues: write jobs: