Ecwid Data Layer Structure for GTM | OpsBlu Docs

Ecwid Data Layer Structure for GTM

Complete reference for Ecwid's data layer structure, events, and how to access them in Google Tag Manager.

Ecwid automatically pushes ecommerce events to the data layer using the Ecwid JavaScript API. This guide provides complete reference for all available data layer events and how to use them in Google Tag Manager.

Data Layer Overview

Ecwid uses a custom data layer structure based on the Ecwid JavaScript API. Unlike Shopify's native data layer, Ecwid requires manual data layer implementation using the API.

How Ecwid Data Layer Works

  1. Ecwid API loads → JavaScript API becomes available
  2. User interactions → API callbacks trigger
  3. Data layer pushes → Events pushed to window.dataLayer
  4. GTM captures → Triggers fire based on events
  5. Tags execute → Send data to analytics platforms

Data Layer Implementation

Ecwid doesn't push to data layer by default. You must implement it using the Ecwid API.

Implementing Ecwid Data Layer

Add this code to Ecwid Control Panel → Settings → General → Tracking & Analytics → Custom JavaScript Code.

Complete Data Layer Implementation

<script>
// Initialize data layer
window.dataLayer = window.dataLayer || [];

// Wait for Ecwid API
Ecwid.OnAPILoaded.add(function() {
  console.log('Ecwid Data Layer Initialized');

  // Push initial page load
  dataLayer.push({
    'event': 'ecwid_loaded',
    'ecwid_store_id': Ecwid.getStorefrontInfo().storeId
  });

  // Product Viewed
  Ecwid.OnPageLoad.add(function(page) {
    if (page.type === 'PRODUCT') {
      Ecwid.getProduct(page.productId, function(product) {
        dataLayer.push({
          'event': 'product_viewed',
          'ecommerce': {
            'currencyCode': product.currency || 'USD',
            'detail': {
              'products': [{
                'id': product.id.toString(),
                'name': product.name,
                'price': product.defaultDisplayedPrice,
                'brand': product.brand || '',
                'category': getCategoryName(product.categoryIds),
                'variant': product.sku || '',
                'dimension1': product.inStock ? 'In Stock' : 'Out of Stock'
              }]
            }
          },
          'product': {
            'id': product.id,
            'name': product.name,
            'price': product.defaultDisplayedPrice,
            'currency': product.currency || 'USD',
            'inStock': product.inStock,
            'url': product.url
          }
        });
      });
    }

    // Category Viewed
    if (page.type === 'CATEGORY') {
      dataLayer.push({
        'event': 'category_viewed',
        'category': {
          'id': page.categoryId,
          'name': 'Category ' + page.categoryId
        }
      });
    }

    // Search Performed
    if (page.type === 'SEARCH') {
      dataLayer.push({
        'event': 'search_performed',
        'search': {
          'term': page.keywords
        }
      });
    }

    // Checkout Started
    if (page.type === 'CHECKOUT_ADDRESS') {
      Ecwid.Cart.get(function(cart) {
        dataLayer.push({
          'event': 'checkout_started',
          'ecommerce': {
            'currencyCode': cart.currency || 'USD',
            'checkout': {
              'actionField': {'step': 1},
              'products': cart.items.map(function(item) {
                return {
                  'id': item.product.id.toString(),
                  'name': item.product.name,
                  'price': item.price,
                  'quantity': item.quantity
                };
              })
            }
          },
          'cart': {
            'total': cart.total,
            'itemCount': cart.items.length,
            'currency': cart.currency || 'USD'
          }
        });
      });
    }
  });

  // Cart Changed (Add to Cart / Remove from Cart)
  var previousCart = null;
  Ecwid.OnCartChanged.add(function(cart) {
    if (previousCart === null) {
      previousCart = JSON.parse(JSON.stringify(cart));
      return;
    }

    // Item Added
    if (cart.items.length > previousCart.items.length) {
      var newItem = cart.items[cart.items.length - 1];

      dataLayer.push({
        'event': 'add_to_cart',
        'ecommerce': {
          'currencyCode': cart.currency || 'USD',
          'add': {
            'products': [{
              'id': newItem.product.id.toString(),
              'name': newItem.product.name,
              'price': newItem.price,
              'quantity': newItem.quantity
            }]
          }
        },
        'product': {
          'id': newItem.product.id,
          'name': newItem.product.name,
          'price': newItem.price,
          'quantity': newItem.quantity
        }
      });
    }

    // Item Removed
    if (cart.items.length < previousCart.items.length) {
      var removedItem = previousCart.items.find(function(prevItem) {
        return !cart.items.some(function(currItem) {
          return currItem.id === prevItem.id;
        });
      });

      if (removedItem) {
        dataLayer.push({
          'event': 'remove_from_cart',
          'ecommerce': {
            'currencyCode': cart.currency || 'USD',
            'remove': {
              'products': [{
                'id': removedItem.product.id.toString(),
                'name': removedItem.product.name,
                'price': removedItem.price,
                'quantity': removedItem.quantity
              }]
            }
          }
        });
      }
    }

    // Update cart reference
    previousCart = JSON.parse(JSON.stringify(cart));

    // Push cart data
    dataLayer.push({
      'event': 'cart_updated',
      'cart': {
        'total': cart.total,
        'itemCount': cart.items.length,
        'currency': cart.currency || 'USD',
        'items': cart.items.map(function(item) {
          return {
            'id': item.product.id,
            'name': item.product.name,
            'price': item.price,
            'quantity': item.quantity
          };
        })
      }
    });
  });

  // Order Placed (Purchase)
  Ecwid.OnOrderPlaced.add(function(order) {
    dataLayer.push({
      'event': 'purchase',
      'ecommerce': {
        'currencyCode': order.currency || 'USD',
        'purchase': {
          'actionField': {
            'id': order.vendorOrderNumber,
            'affiliation': 'Ecwid Store',
            'revenue': order.total,
            'tax': order.tax || 0,
            'shipping': order.shippingOption ? order.shippingOption.shippingRate : 0,
            'coupon': order.couponDiscount > 0 ? order.couponName : ''
          },
          'products': order.items.map(function(item) {
            return {
              'id': item.product.id.toString(),
              'name': item.product.name,
              'price': item.price,
              'quantity': item.quantity,
              'category': item.product.categoryIds ? 'Category ' + item.product.categoryIds[0] : ''
            };
          })
        }
      },
      'transaction': {
        'id': order.vendorOrderNumber,
        'total': order.total,
        'tax': order.tax || 0,
        'shipping': order.shippingOption ? order.shippingOption.shippingRate : 0,
        'currency': order.currency || 'USD',
        'email': order.email,
        'itemCount': order.items.length
      }
    });
  });

  // Helper function
  function getCategoryName(categoryIds) {
    if (!categoryIds || categoryIds.length === 0) return '';
    return 'Category ' + categoryIds[0];
  }

});
</script>

Add this code to Ecwid's Custom JavaScript Code section to enable all data layer events.

Ecwid Data Layer Events

1. ecwid_loaded

Fires when Ecwid API is ready.

Data Layer Push:

{
  'event': 'ecwid_loaded',
  'ecwid_store_id': 12345678
}

GTM Trigger:

  • Type: Custom Event
  • Event name: ecwid_loaded

Use case: Initialize tags that depend on Ecwid being loaded.

2. product_viewed

Fires when customer views a product detail page.

Data Layer Push:

{
  'event': 'product_viewed',
  'ecommerce': {
    'currencyCode': 'USD',
    'detail': {
      'products': [{
        'id': '123456',
        'name': 'Product Name',
        'price': 29.99,
        'brand': 'Brand Name',
        'category': 'Category Name',
        'variant': 'SKU-123'
      }]
    }
  },
  'product': {
    'id': 123456,
    'name': 'Product Name',
    'price': 29.99,
    'currency': 'USD',
    'inStock': true,
    'url': 'https://store.com/product'
  }
}

GTM Variables:

Create Data Layer Variables:

  • ecommerce.detail.products.0.id → "Product ID"
  • ecommerce.detail.products.0.name → "Product Name"
  • ecommerce.detail.products.0.price → "Product Price"
  • product.inStock → "Product In Stock"

GTM Trigger:

  • Type: Custom Event
  • Event name: product_viewed

3. category_viewed

Fires when customer views a category page.

Data Layer Push:

{
  'event': 'category_viewed',
  'category': {
    'id': 12345,
    'name': 'Category Name'
  }
}

GTM Variables:

  • category.id → "Category ID"
  • category.name → "Category Name"

GTM Trigger:

  • Type: Custom Event
  • Event name: category_viewed

4. search_performed

Fires when customer uses search.

Data Layer Push:

{
  'event': 'search_performed',
  'search': {
    'term': 'customer search query'
  }
}

GTM Variable:

  • search.term → "Search Term"

GTM Trigger:

  • Type: Custom Event
  • Event name: search_performed

5. add_to_cart

Fires when item is added to cart.

Data Layer Push:

{
  'event': 'add_to_cart',
  'ecommerce': {
    'currencyCode': 'USD',
    'add': {
      'products': [{
        'id': '123456',
        'name': 'Product Name',
        'price': 29.99,
        'quantity': 1
      }]
    }
  },
  'product': {
    'id': 123456,
    'name': 'Product Name',
    'price': 29.99,
    'quantity': 1
  }
}

GTM Variables:

  • ecommerce.add.products.0.id → "Added Product ID"
  • ecommerce.add.products.0.name → "Added Product Name"
  • ecommerce.add.products.0.price → "Added Product Price"
  • product.quantity → "Added Product Quantity"

GTM Trigger:

  • Type: Custom Event
  • Event name: add_to_cart

6. remove_from_cart

Fires when item is removed from cart.

Data Layer Push:

{
  'event': 'remove_from_cart',
  'ecommerce': {
    'currencyCode': 'USD',
    'remove': {
      'products': [{
        'id': '123456',
        'name': 'Product Name',
        'price': 29.99,
        'quantity': 1
      }]
    }
  }
}

GTM Trigger:

  • Type: Custom Event
  • Event name: remove_from_cart

7. cart_updated

Fires whenever cart changes (add, remove, quantity change).

Data Layer Push:

{
  'event': 'cart_updated',
  'cart': {
    'total': 89.97,
    'itemCount': 3,
    'currency': 'USD',
    'items': [
      {
        'id': 123456,
        'name': 'Product 1',
        'price': 29.99,
        'quantity': 2
      },
      {
        'id': 789012,
        'name': 'Product 2',
        'price': 29.99,
        'quantity': 1
      }
    ]
  }
}

GTM Variables:

  • cart.total → "Cart Total"
  • cart.itemCount → "Cart Item Count"
  • cart.currency → "Cart Currency"

GTM Trigger:

  • Type: Custom Event
  • Event name: cart_updated

8. checkout_started

Fires when checkout process begins.

Data Layer Push:

{
  'event': 'checkout_started',
  'ecommerce': {
    'currencyCode': 'USD',
    'checkout': {
      'actionField': {'step': 1},
      'products': [{
        'id': '123456',
        'name': 'Product Name',
        'price': 29.99,
        'quantity': 1
      }]
    }
  },
  'cart': {
    'total': 29.99,
    'itemCount': 1,
    'currency': 'USD'
  }
}

GTM Trigger:

  • Type: Custom Event
  • Event name: checkout_started

9. purchase

Fires when order is completed.

Data Layer Push:

{
  'event': 'purchase',
  'ecommerce': {
    'currencyCode': 'USD',
    'purchase': {
      'actionField': {
        'id': 'ORDER-12345',
        'affiliation': 'Ecwid Store',
        'revenue': 89.97,
        'tax': 7.50,
        'shipping': 10.00,
        'coupon': 'SAVE10'
      },
      'products': [{
        'id': '123456',
        'name': 'Product Name',
        'price': 29.99,
        'quantity': 3,
        'category': 'Category Name'
      }]
    }
  },
  'transaction': {
    'id': 'ORDER-12345',
    'total': 89.97,
    'tax': 7.50,
    'shipping': 10.00,
    'currency': 'USD',
    'email': 'customer@example.com',
    'itemCount': 3
  }
}

GTM Variables:

  • ecommerce.purchase.actionField.id → "Transaction ID"
  • ecommerce.purchase.actionField.revenue → "Transaction Revenue"
  • transaction.email → "Customer Email"

GTM Trigger:

  • Type: Custom Event
  • Event name: purchase

Creating GTM Variables

Data Layer Variables

For simple values directly in data layer:

Example: Product ID

  1. Variables → New
  2. Variable Type: Data Layer Variable
  3. Data Layer Variable Name: ecommerce.detail.products.0.id
  4. Data Layer Version: Version 2
  5. Name: DLV - Product ID
  6. Save

Example: Cart Total

  1. Variables → New
  2. Variable Type: Data Layer Variable
  3. Data Layer Variable Name: cart.total
  4. Name: DLV - Cart Total
  5. Save

Custom JavaScript Variables

For complex transformations:

Example: Product Items Array for GA4

function() {
  var dl = {{Event}};

  // For product_viewed
  if (dl && dl.ecommerce && dl.ecommerce.detail) {
    var products = dl.ecommerce.detail.products || [];
    return products.map(function(p) {
      return {
        item_id: p.id,
        item_name: p.name,
        item_brand: p.brand || '',
        item_category: p.category || '',
        price: parseFloat(p.price),
        quantity: 1
      };
    });
  }

  // For add_to_cart
  if (dl && dl.ecommerce && dl.ecommerce.add) {
    var products = dl.ecommerce.add.products || [];
    return products.map(function(p) {
      return {
        item_id: p.id,
        item_name: p.name,
        price: parseFloat(p.price),
        quantity: p.quantity
      };
    });
  }

  return [];
}

Variable Type: Custom JavaScript Name: CJS - GA4 Items Array

Common GTM Variables for Ecwid

Create these variables for easy reuse:

Variable Name Type Data Layer Path
DLV - Product ID Data Layer ecommerce.detail.products.0.id
DLV - Product Name Data Layer ecommerce.detail.products.0.name
DLV - Product Price Data Layer ecommerce.detail.products.0.price
DLV - Product Category Data Layer ecommerce.detail.products.0.category
DLV - Cart Total Data Layer cart.total
DLV - Cart Item Count Data Layer cart.itemCount
DLV - Currency Data Layer ecommerce.currencyCode
DLV - Transaction ID Data Layer ecommerce.purchase.actionField.id
DLV - Revenue Data Layer ecommerce.purchase.actionField.revenue
DLV - Search Term Data Layer search.term

Creating GTM Triggers

Product Viewed Trigger

Trigger Configuration:

  • Type: Custom Event
  • Event name: product_viewed

Name: Ecwid - Product Viewed

Add to Cart Trigger

Trigger Configuration:

  • Type: Custom Event
  • Event name: add_to_cart

Name: Ecwid - Add to Cart

Purchase Trigger

Trigger Configuration:

  • Type: Custom Event
  • Event name: purchase

Name: Ecwid - Purchase

All Ecwid Triggers

Create triggers for:

  • ecwid_loaded
  • product_viewed
  • category_viewed
  • search_performed
  • add_to_cart
  • remove_from_cart
  • cart_updated
  • checkout_started
  • purchase

Example Tag Configurations

GA4 View Item Event

Tag Type: Google Analytics: GA4 Event

Configuration:

  • Configuration Tag: GA4 - Configuration
  • Event Name: view_item

Event Parameters:

  • currency: \{\{DLV - Currency\}\}
  • value: \{\{DLV - Product Price\}\}
  • items: \{\{CJS - GA4 Items Array\}\}

Trigger: Ecwid - Product Viewed

GA4 Purchase Event

Tag Type: Google Analytics: GA4 Event

Configuration:

  • Configuration Tag: GA4 - Configuration
  • Event Name: purchase

Event Parameters:

  • transaction_id: \{\{DLV - Transaction ID\}\}
  • value: \{\{DLV - Revenue\}\}
  • currency: \{\{DLV - Currency\}\}
  • tax: \{\{ecommerce.purchase.actionField.tax\}\}
  • shipping: \{\{ecommerce.purchase.actionField.shipping\}\}
  • items: \{\{CJS - GA4 Purchase Items Array\}\}

Trigger: Ecwid - Purchase

Meta Pixel ViewContent Event

Tag Type: Custom HTML

HTML:

<script>
fbq('track', 'ViewContent', {
  content_ids: ['{{DLV - Product ID}}'],
  content_name: '{{DLV - Product Name}}',
  content_type: 'product',
  value: {{DLV - Product Price}},
  currency: '{{DLV - Currency}}'
});
</script>

Trigger: Ecwid - Product Viewed

Debugging Data Layer

View Data Layer in Console

// View entire data layer
console.table(window.dataLayer);

// Filter specific event
window.dataLayer.filter(obj => obj.event === 'product_viewed');

// Monitor new pushes
var originalPush = window.dataLayer.push;
window.dataLayer.push = function() {
  console.log('Data Layer Push:', arguments[0]);
  return originalPush.apply(window.dataLayer, arguments);
};

GTM Preview Mode

  1. Enable Preview in GTM
  2. Navigate to store
  3. Click event in Tag Assistant
  4. View Data Layer tab
  5. Verify values populate

Common Issues

Data Layer is Empty

Cause: Ecwid API not loaded or data layer code not added.

Fix:

  1. Add complete data layer implementation code (see above)
  2. Verify code is in Custom JavaScript Code section
  3. Check console for JavaScript errors

Variables Return Undefined

Cause: Data layer path incorrect or event hasn't fired.

Fix:

  • Verify exact data layer path
  • Check that event has fired before variable accessed
  • Use GTM Preview to inspect data layer

Events Fire Multiple Times

Cause: Multiple data layer implementations or page reloads.

Fix:

  • Use flags to prevent duplicates
  • Check for multiple GTM containers
  • Remove duplicate implementations

Best Practices

1. Clear Event Names

Use descriptive, consistent event names:

  • product_viewed (not productView or view_product)
  • add_to_cart (not addCart or cartAdd)

2. Consistent Data Structure

Keep ecommerce object structure consistent across events.

3. Include Currency

Always include currency code with monetary values.

4. String vs Number

  • IDs: Always strings
  • Prices: Always numbers
  • Quantities: Always numbers

5. Error Handling

Add error handling to data layer code:

try {
  dataLayer.push({...});
} catch (e) {
  console.error('Data Layer Push Error:', e);
}

Next Steps

For general data layer concepts, see Data Layer Guide.