Spree Commerce is an open-source Ruby on Rails ecommerce platform. It provides full access to ERB templates, a gem-based extension system, and both traditional server-rendered and headless (Storefront API) delivery models. Analytics integration uses Rails view templates, Spree's decorator/override system, or gem-based extensions.
Integration Architecture
Spree Commerce provides four integration paths:
- ERB Layout Templates -- Edit the application layout at
app/views/spree/layouts/spree_application.html.erb(or its override in your extension). Standard Rails ERB templating with Spree view helpers. - Spree Extensions (Gems) -- Install analytics gems via
Gemfile. Extensions likespree_analytics_trackersprovide admin-configurable tracking. - Deface Overrides -- Spree uses the Deface gem to modify views without editing core files. Add tracking scripts via Deface overrides that inject content into layout templates.
- Storefront API (Headless) -- Spree's REST/GraphQL API serves product and order data. Frontend frameworks consuming this API handle analytics independently.
Available Integrations
Analytics Platforms
- ERB layout template injection
spree_analytics_trackersgem (admin-configurable)- GTM-based GA4 with Spree data layer (recommended)
Tag Management
- Application layout ERB injection
- Deface override for non-invasive injection
Marketing Pixels
- Via GTM container (recommended)
- ERB template head injection
ERB Layout Integration with Ecommerce Data Layer
Edit the Spree application layout to add GTM and an ecommerce data layer:
<%# app/views/spree/layouts/spree_application.html.erb %>
<!DOCTYPE html>
<html lang="<%= I18n.locale %>">
<head>
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;
j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;
f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer','GTM-XXXX');</script>
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'pageType': '<%= controller_name %>',
'actionName': '<%= action_name %>',
'currency': '<%= current_currency %>',
'locale': '<%= I18n.locale %>',
'userLoggedIn': <%= spree_current_user ? 'true' : 'false' %>,
'storeName': '<%= current_store.name %>'
});
</script>
<%= yield :head %>
</head>
<body>
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<%= yield %>
</body>
</html>
On the product page, add a view_item event in app/views/spree/products/show.html.erb:
<% content_for :head do %>
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'view_item',
ecommerce: {
currency: '<%= current_currency %>',
value: <%= @product.price.to_f %>,
items: [{
item_id: '<%= @product.sku || @product.id %>',
item_name: '<%= j @product.name %>',
price: <%= @product.price.to_f %>,
item_category: '<%= j(@product.taxons.first&.name || "") %>'
}]
}
});
</script>
<% end %>
Platform Limitations
Deface complexity. Spree uses Deface for view overrides, which targets specific DOM elements in ERB templates using CSS selectors. If Spree updates its template HTML structure, Deface overrides can silently break. Pin your Spree version and test overrides after upgrades.
Order confirmation data. Spree's order confirmation page (orders#show after checkout) provides order data via @order. However, page refreshes re-render the order page without re-triggering the checkout flow, potentially causing duplicate purchase events. Use a flag (cookie or session) to fire the purchase event only once.
Gem compatibility. The spree_analytics_trackers gem may lag behind Spree core releases. Verify gem compatibility with your Spree version before installing.
Headless Spree. When using Spree as a headless backend (Storefront API), the ERB template integration does not apply. Analytics integration happens in your React/Next.js/Vue frontend using standard SPA tracking patterns.
Multi-store. Spree supports multiple stores from one installation. Each store can have different currencies, locales, and product catalogs. Ensure your data layer includes the store identifier for cross-store analytics segmentation.
Performance Considerations
- Rails asset pipeline. Spree uses the Rails asset pipeline (Sprockets or Webpacker) for CSS/JS bundling. Third-party tracking scripts bypass this pipeline and load as separate HTTP requests.
- Turbolinks/Turbo. If using Turbolinks or Hotwire Turbo with Spree, page navigations are AJAX-based without full reloads. GTM's standard pageview trigger fires only on initial load. Listen for
turbolinks:loadorturbo:loadevents for subsequent page views. - N+1 queries. Data layer construction that accesses product associations (
@product.taxons,@product.variants) can trigger N+1 queries. Use eager loading (includes(:taxons)) in controllers.
Recommended Integration Priority
- Add GTM to application layout -- Global coverage for all Spree pages
- Build ecommerce data layer -- Product, cart, and purchase events on relevant pages
- Handle Turbolinks/Turbo -- Fire virtual pageviews on SPA-like navigations
- Configure GA4 ecommerce in GTM -- Map Spree product data to GA4 ecommerce
- Add Meta Pixel via GTM -- Map ecommerce events to Meta standard events
Next Steps
For general integration concepts, see the integrations overview.