Shopware
These instructions cover Shopware 6. Shopware does not ship an admin field for arbitrary head scripts, so the snippet goes in through your theme (a small Twig override), and purchases are recorded on the checkout finish page where the order is available to the template.
Install the snippet
Your snippet comes from Project Settings → Snippet in the A vs B dashboard:
<script>window.avsb=window.avsb||{};window.avsb.q=window.avsb.q||[];window.avsb.ready=window.avsb.ready||function(f){window.avsb.q.push(f)};window.avsb.on=window.avsb.on||function(n,f){var t=['on',n,f];window.avsb.q.push(t);return function(){t[0]=null}};window.avsb.consent=window.avsb.consent||{set:function(s){window.avsb.q.push(['consent.set',s])},get:function(){return{}}};window.avsb.track=window.avsb.track||{};['event','segment','purchase','cart'].forEach(function(m){window.avsb.track[m]=window.avsb.track[m]||function(a,b){window.avsb.q.push(['track.'+m,a,b])}});(function(){window.avsb._t0=Date.now();window.avsb._df=fetch('https://cdn.avsb.cloud/YOUR_SNIPPET_KEY/datafile.json').catch(function(){});var d=document,e=d.documentElement,s=d.currentScript,a=s&&s.getAttribute('data-avsb-timeout'),t=a==null?3000:+a;if(!(t>0)||window.avsb.version)return;e.style.opacity='0';e.style.pointerEvents='none';window.avsb._t=setTimeout(function(){e.style.removeProperty('opacity');e.style.removeProperty('pointer-events')},t)})();</script><script src="https://cdn.avsb.cloud/snippet.js?id=YOUR_SNIPPET_KEY" data-avsb="YOUR_SNIPPET_KEY" async></script>The first tag is a stub that makes avsb.ready(...), avsb.on(...) and avsb.consent.set(...) calls safe before the bundle loads. Include both in your Twig override.
Override the head template in your theme
In your theme (or a small storefront plugin), create src/Resources/views/storefront/layout/meta.html.twig to extend the Storefront's head template.
Add the script tag
Extend the head block and inject the snippet tag, keeping the parent content: see the Twig example below this list.
Compile the theme
Run bin/console theme:compile (or redeploy your theme) and clear the cache so the change reaches the storefront.
Verify
Load your storefront, then check Project Settings → Snippet in A vs B: the status turns green once the snippet has been detected.
{% sw_extends '@Storefront/storefront/layout/meta.html.twig' %}{% block layout_head_javascript_tracking %} {{ parent() }} <script> window.avsb=window.avsb||{};window.avsb.q=window.avsb.q||[]; window.avsb.ready=window.avsb.ready||function(f){window.avsb.q.push(f)}; window.avsb.on=window.avsb.on||function(n,f){var t=['on',n,f];window.avsb.q.push(t);return function(){t[0]=null}}; window.avsb.consent=window.avsb.consent||{set:function(s){window.avsb.q.push(['consent.set',s])},get:function(){return{}}}; window.avsb.track=window.avsb.track||{};['event','segment','purchase','cart'].forEach(function(m){window.avsb.track[m]=window.avsb.track[m]||function(a,b){window.avsb.q.push(['track.'+m,a,b])}}); (function(){window.avsb._t0=Date.now();window.avsb._df=fetch('https://cdn.avsb.cloud/YOUR_SNIPPET_KEY/datafile.json').catch(function(){});var d=document,e=d.documentElement,s=d.currentScript,a=s&&s.getAttribute('data-avsb-timeout'),t=a==null?3000:+a;if(!(t>0)||window.avsb.version)return;e.style.opacity='0';e.style.pointerEvents='none';window.avsb._t=setTimeout(function(){e.style.removeProperty('opacity');e.style.removeProperty('pointer-events')},t)})(); </script> <script src="https://cdn.avsb.cloud/snippet.js?id=YOUR_SNIPPET_KEY" data-avsb="YOUR_SNIPPET_KEY" async></script>{% endblock %}The exact head block names in meta.html.twig have shifted across Shopware 6 minor versions. Open the file in your installed Storefront bundle and extend whichever block renders scripts in the head: the snippet just needs to load early on every page.
Record purchases
Override the checkout finish page, where page.order is available, and call avsb.track.purchase:
{% sw_extends '@Storefront/storefront/page/checkout/finish/index.html.twig' %}{% block page_checkout_finish %} {{ parent() }} <script> avsb.ready(function () { avsb.track.purchase({ orderId: '{{ page.order.orderNumber }}', total: {{ page.order.amountTotal }}, currency: '{{ page.order.currency.isoCode }}', shipping: {{ page.order.shippingTotal }} }); }); </script>{% endblock %}The fields:
orderId: required. Orders are deduplicated by this ID (last write wins), so a refresh of the finish page never double-counts.total: required. The order total as a decimal, for example49.99.currency: optional. Defaults to your project's configured currency if omitted.
If a GTM/GA4 extension on your store already pushes the GA4 purchase event to window.dataLayer, and your product catalog is connected, you can skip the template override: turn on Google Analytics 4 / dataLayer on your project's Product catalog page and the snippet records those purchases automatically. Running both is harmless: orders are deduplicated by ID.
Verify
Place a test order, then open Commerce → Orders in the A vs B dashboard (see the orders & attribution guide) to confirm the order arrived and was attributed to an experiment exposure.