webburza/sylius-google-ecommerce-bundle
Integrates Google Analytics Enhanced Ecommerce with Sylius, automatically tracking product impressions, detail views, cart additions and removals, checkout steps, and purchases so you can analyze shopping behavior and conversions without writing custom tracking code.
The bundle wires Sylius storefront templates to Google Analytics Enhanced E-Commerce calls (analytics.js era: ga('ec:addProduct', ...), ga('ec:setAction', ...)). It is a thin Twig/template layer, not an analytics backend — expect to render tracking payloads from your existing Sylius templates.
First steps:
composer require it cleanly.composer require webburza/sylius-google-ecommerce-bundle
Register Webburza\SyliusGoogleEcommerceBundle\SyliusGoogleEcommerceBundle in AppKernel (or config/bundles.php if you have forward-ported it).webburza_google_ecommerce.tracking_id: UA-XXXXX-Y. Confirm the bundle's Configuration.php for the exact key before wiring it.Resources/views/ in the bundle to see which Sylius templates it overrides or provides partials for, and at its Twig extension/service definitions. That's the contract you'll build on.SyliusShopBundle:Product:show.html.twig, call the bundle's tracking helper with the current product (SKU, name, category, price, variant), and verify a detail action fires with the ec payload in GA Debugger.Template-level tracking (the intended path). The bundle expects you to invoke tracking from Sylius shop templates. The practical pattern is a small Twig macro that accepts a Sylius Product/Variant and outputs the GA product object once, then reuses it across listing, detail, cart, and checkout templates. Centralising this avoids drift in SKU/category/price fields between pages.
Impressions on listing pages. On product list/search templates, loop products and emit ec:addImpression with id, name, category, position. Position should come from the loop index — GA uses it for click-through attribution, so keep it stable across pagination.
Click and add-to-cart. Track product clicks on listing links (ec:setAction('click', ...)) and render add-to-cart payloads on the product detail template. Since Sylius add-to-cart is typically a form POST + redirect, the most reliable pattern is to render the addToCart action with the product data on the detail page rather than trying to reconstruct it post-redirect. If you have AJAX cart, hook the returned cart item in JS.
Cart deltas. On the cart page, emit ec:addProduct + ec:setAction('add'|'remove') based on what changed. The simplest day-to-day approach is a service or Twig helper that decorates Sylius OrderItem into a GA payload (id, name, category, variant, price, quantity). For quantity-change tracking, compare against a session-stored previous quantity or emit 'add'/'remove' on the specific line-item form submission.
Checkout funnel steps. Map Sylius checkout steps (address, select_shipping, select_payment, summary) to GA checkout actions with step numbers in the checkout layout. Keep the numbering in a single Twig variable or config map so reordering Sylius steps doesn't silently break the funnel.
Purchase on order confirmation. On the SyliusShopBundle:Checkout:thankyou (order complete) template, pass the Order in: id (order number), affiliation, revenue (grand total), tax, shipping, and each OrderItem as a product. This is the highest-value call and the one most worth testing end-to-end.
Integration tip — dataLayer-first if on GTM. If your storefront runs GTM or gtag rather than raw analytics.js, keep the bundle's product-mapping logic but render dataLayer.push({ ecommerce: {...} }) instead of ga('ec:...'). The mapping code is the reusable part; the transport is what changes.
ga) calls; UA stopped processing hits in July 2023. Treat it as a reference implementation for the Enhanced E-Commerce payload shape, and plan to port the output to GA4 (gtag/dataLayer). Don't expect the package to "just track" on a new project.composer.json constraints first; on modern Sylius you'll likely fork it into your src/ or vendor-patch it.ec:addProduct/ec:setAction must precede the pageview (or an explicit ga('send', 'pageview')) for the hit to carry ecommerce data. If you inject the bundle's partial in the wrong block, you get pageviews with no ecommerce data — the classic "tracking looks fine but ecommerce columns are empty" issue.ga('require', 'ec', ...) currency once.variant.code (or product code) consistently to id in every action. Mixing product code on detail with variant code in cart breaks product-level reports.ga('set', 'sendHitTask', ...) / ?gtm_debug=1 for GTM), watch the /collect network requests, and use GA's real-time Ecommerce report. Verify each of impressions → click → detail → add → checkout step → purchase in order.app/Resources/.../views/) and overriding config, rather than editing vendor files. If you're forking, extract the product/order → GA payload mapping into your own Twig extension or service so the analytics transport can be swapped without touching templates.How can I help you explore Laravel packages today?