Spreecommerce Troubleshooting: Common Issues and Fixes | OpsBlu Docs

Spreecommerce Troubleshooting: Common Issues and Fixes

Debug analytics issues on Spree Commerce — Rails asset pipeline conflicts, Deface overrides, Turbo/Turbolinks navigation tracking, and ecommerce...

Spree Commerce is a Ruby on Rails-based open-source ecommerce platform. Analytics issues on Spree typically involve the Rails asset pipeline (Sprockets/Propshaft) modifying JavaScript, Turbo (or Turbolinks in older versions) intercepting page navigation, Deface overrides not injecting tracking code correctly, and the complexity of building an ecommerce dataLayer from Spree's order/product models.

Spree-Specific Debugging Approach

Spree is a Rails engine. Your storefront is a Rails app that mounts the Spree engine. Analytics code can be injected through the Rails layout, Deface overrides, or Spree extensions.

Check the Rails Layout

# SSH into your Spree server

# Find the main application layout
find app/views/layouts -name "*.html.erb" -o -name "*.html.slim" -o -name "*.html.haml" | head -5

# Check for analytics in the layout
grep -rn "gtag\|gtm\|analytics\|dataLayer" app/views/layouts/

# Check Spree's default layout (if not overridden)
grep -rn "gtag\|gtm\|analytics" $(bundle show spree_frontend)/app/views/layouts/ 2>/dev/null
// In browser console, check if Turbo or Turbolinks is active
console.log('Turbo:', typeof Turbo !== 'undefined' ? 'Active' : 'Not found');
console.log('Turbolinks:', typeof Turbolinks !== 'undefined' ? 'Active' : 'Not found');
console.log('Page visits:', performance.getEntriesByType('navigation')[0]?.type);

// Check if analytics scripts are in the head
document.querySelectorAll('script[src*="gtag"], script[src*="gtm"]').forEach(s => {
  console.log('Analytics:', s.src, '| data-turbo-track:', s.dataset.turboTrack || 'none');
});

Most Common Spree Analytics Issues

Symptoms: Only the first page load fires a pageview. Navigating between pages (products, categories, cart) shows no additional analytics hits.

Root cause: Spree 4.x+ uses Turbo (or Turbolinks in 3.x). These libraries intercept link clicks and replace the <body> without a full page reload, so gtag.js never re-fires.

Fix: Listen for Turbo navigation events:

// For Spree 4.x+ with Turbo
document.addEventListener('turbo:load', function() {
  gtag('event', 'page_view', {
    page_path: window.location.pathname,
    page_title: document.title
  });
});

// For older Spree with Turbolinks
document.addEventListener('turbolinks:load', function() {
  gtag('event', 'page_view', {
    page_path: window.location.pathname,
    page_title: document.title
  });
});

2. Asset Pipeline Mangling Analytics JavaScript

Symptoms: Analytics JavaScript has syntax errors after deployment. Works in development but breaks in production.

Root cause: Rails' asset pipeline (Sprockets) can mangle JavaScript during compression/minification. Terser or UglifyJS may break non-standard JavaScript patterns.

Fix: Exclude analytics from the asset pipeline by loading it directly:

<%# In app/views/layouts/application.html.erb %>
<head>
  <%= csrf_meta_tags %>
  <%= csp_meta_tag %>

  <%# Load analytics OUTSIDE the asset pipeline %>
  <script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX" data-turbo-track="reload"></script>
  <script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'G-XXXXXXX');
  </script>

  <%= stylesheet_link_tag 'application' %>
  <%= javascript_include_tag 'application', 'data-turbo-track': 'reload' %>
</head>

3. Ecommerce DataLayer Missing Order Data

Symptoms: Pageviews track but purchase events have no revenue, product, or transaction data.

Root cause: Spree's order confirmation page needs to expose order data to the analytics dataLayer. This is not automatic — you must extract data from Spree's @order object.

Fix: Create a partial for the order confirmation page:

<%# In app/views/spree/checkout/complete.html.erb (or via Deface override) %>
<script>
dataLayer.push({
  'event': 'purchase',
  'ecommerce': {
    'transaction_id': '<%= @order.number %>',
    'value': <%= @order.total.to_f %>,
    'currency': '<%= @order.currency %>',
    'shipping': <%= @order.ship_total.to_f %>,
    'tax': <%= @order.tax_total.to_f %>,
    'items': [
      <% @order.line_items.each_with_index do |item, i| %>
      {
        'item_id': '<%= item.variant.sku %>',
        'item_name': '<%= j(item.product.name) %>',
        'price': <%= item.price.to_f %>,
        'quantity': <%= item.quantity %>
      }<%= ',' unless i == @order.line_items.size - 1 %>
      <% end %>
    ]
  }
});
</script>

4. Deface Override Not Injecting Code

Symptoms: You created a Deface override to inject analytics but it does not appear in the rendered page.

Root cause: Deface overrides target specific selectors in Spree's views. If Spree's view structure changed in an upgrade, or if your storefront uses a custom theme that replaced the default views, the Deface selector no longer matches.

Diagnosis:

# Check if Deface overrides are loading
rails console
Deface::Override.all.each { |k, v| puts "#{k}: #{v.map(&:name).join(', ')}" }

# Check the target view exists
find $(bundle show spree_frontend)/app/views -name "*.erb" | head -20

Fix: Update the Deface selector to match your current view structure, or inject directly into your layout instead.

5. Spree API Storefront (Headless) Not Tracking

Symptoms: Using Spree's API with a JavaScript frontend (React, Vue, Next.js). No analytics tracking at all.

Root cause: Spree's headless API mode serves JSON, not HTML. The Rails layout with analytics code never renders.

Fix: Implement analytics entirely in your JavaScript frontend, using Spree API response data:

// After fetching order confirmation from Spree API
const order = await spreeClient.checkout.complete(orderToken);
gtag('event', 'purchase', {
  transaction_id: order.data.attributes.number,
  value: parseFloat(order.data.attributes.total),
  currency: order.data.attributes.currency
});

Environment Considerations

  • Ruby/Rails version: Spree 4.x requires Rails 6+/7+. Older Spree versions may use Turbolinks instead of Turbo, and Sprockets instead of Propshaft
  • Spree extensions: Analytics extensions like spree_analytics_trackers exist but may not support GA4. Check compatibility before installing
  • Docker development: Many Spree setups use Docker. Ensure analytics configuration survives container rebuilds by placing it in version-controlled files, not in the database
  • Spree Commerce vs Solidus: Solidus is a fork of Spree. The analytics approach is similar but template paths differ
  • Redis/Sidekiq: Spree uses background jobs for order processing. Analytics must fire from the client-side confirmation page, not from a background job

Performance Issues

  • LCP Issues - Rails rendering overhead, asset pipeline loading, and Turbo prefetch timing
  • CLS Issues - Layout shifts from Turbo page swaps and dynamic cart widget updates

Tracking Issues

  • Events Not Firing - Debug Turbo navigation, asset pipeline conflicts, and ecommerce dataLayer gaps