Enhanced Ecommerce Tracking | OpsBlu Docs

Enhanced Ecommerce Tracking

Implement complete GA4 ecommerce tracking for OSCommerce sales funnel and revenue analytics

Overview

GA4 Enhanced Ecommerce provides comprehensive tracking of the customer journey from product discovery to purchase completion. This includes:

  • Product impressions and clicks
  • Add to cart and remove from cart
  • Checkout steps and abandonment
  • Transaction and revenue tracking
  • Refunds (manual implementation)

Prerequisites

  • GA4 base code installed (See Setup Guide)
  • FTP/File access to OSCommerce files
  • Complete site backup before modifications
  • Understanding of PHP and OSCommerce file structure

Product Impression Tracking

Track when products are viewed in listings (category pages, search results).

Category Page Impressions

File: product_listing.php or index.php (for category pages)

Add after product query results:

<?php
// After products are loaded into $listing array
if (isset($listing) && is_array($listing)) {
?>
<script>
gtag('event', 'view_item_list', {
  'item_list_id': 'category_<?php echo (int)$current_category_id; ?>',
  'item_list_name': '<?php echo addslashes($category_name); ?>',
  'items': [
    <?php
    $items = array();
    foreach ($listing as $index => $product) {
      $items[] = sprintf(
        '{
          "item_id": "%s",
          "item_name": "%s",
          "price": %s,
          "index": %d,
          "quantity": 1
        }',
        $product['products_id'],
        addslashes($product['products_name']),
        $product['products_price'],
        $index
      );
    }
    echo implode(',', $items);
    ?>
  ]
});
</script>
<?php
}
?>

Search Results Impressions

File: advanced_search_result.php

<?php
// After search results loaded
if (isset($listing_query)) {
?>
<script>
gtag('event', 'view_item_list', {
  'item_list_id': 'search_results',
  'item_list_name': 'Search: <?php echo addslashes($_GET['keywords']); ?>',
  'items': [
    <?php
    $items = array();
    while ($listing = tep_db_fetch_array($listing_query)) {
      $items[] = sprintf(
        '{
          "item_id": "%s",
          "item_name": "%s",
          "price": %s
        }',
        $listing['products_id'],
        addslashes($listing['products_name']),
        $listing['products_price']
      );
    }
    echo implode(',', $items);
    ?>
  ]
});
</script>
<?php
}
?>

Product Detail View Tracking

File: product_info.php

Add after product information is loaded:

<?php
// After $product_info is loaded
if (tep_not_null($product_info)) {
  // Get category name
  $categories_query = tep_db_query("SELECT cd.categories_name FROM " . TABLE_CATEGORIES_DESCRIPTION . " cd, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c WHERE p2c.products_id = '" . (int)$product_info['products_id'] . "' AND p2c.categories_id = cd.categories_id AND cd.language_id = '" . (int)$languages_id . "' LIMIT 1");
  $categories = tep_db_fetch_array($categories_query);
  $category_name = $categories ? $categories['categories_name'] : '';

  // Get manufacturer/brand
  $manufacturer_name = isset($product_info['manufacturers_name']) ? $product_info['manufacturers_name'] : '';
?>
<script>
gtag('event', 'view_item', {
  'currency': '<?php echo $_SESSION['currency']; ?>',
  'value': <?php echo $product_info['products_price']; ?>,
  'items': [{
    'item_id': '<?php echo $product_info['products_id']; ?>',
    'item_name': '<?php echo addslashes($product_info['products_name']); ?>',
    'item_category': '<?php echo addslashes($category_name); ?>',
    'item_brand': '<?php echo addslashes($manufacturer_name); ?>',
    'price': <?php echo $product_info['products_price']; ?>,
    'quantity': 1
  }]
});
</script>
<?php
}
?>

Add to Cart Tracking

OSCommerce uses different methods for add to cart depending on version and customization.

Method 1: Standard Form Submission

File: product_info.php

Add JavaScript to track form submission:

<!-- Find the add to cart form -->
<form name="cart_quantity" action="shopping_cart.php" method="post"
  <!-- form fields -->
  <input type="hidden" name="products_id" value="<?php echo $product_info['products_id']; ?>">
  <input type="text" name="cart_quantity" value="1" id="cart_qty">
  <button type="submit" name="add_to_cart">Add to Cart</button>
</form>

<script>
function trackAddToCart() {
  var quantity = parseInt(document.getElementById('cart_qty').value) || 1;

  gtag('event', 'add_to_cart', {
    'currency': '<?php echo $_SESSION['currency']; ?>',
    'value': <?php echo $product_info['products_price']; ?> * quantity,
    'items': [{
      'item_id': '<?php echo $product_info['products_id']; ?>',
      'item_name': '<?php echo addslashes($product_info['products_name']); ?>',
      'price': <?php echo $product_info['products_price']; ?>,
      'quantity': quantity
    }]
  });

  return true; // Allow form submission to continue
}
</script>

Method 2: AJAX Add to Cart

If your OSCommerce store uses AJAX for cart operations:

File: product_info.php or custom JavaScript file

<script>
// Override default add to cart function
function addToCart(productId, productName, productPrice) {
  var quantity = parseInt($('input[name="cart_quantity"]').val()) || 1;

  $.ajax({
    url: 'shopping_cart.php',
    method: 'POST',
    data: {
      action: 'add_product',
      products_id: productId,
      cart_quantity: quantity
    },
    success: function(response) {
      // Track successful add to cart
      gtag('event', 'add_to_cart', {
        'currency': '<?php echo $_SESSION['currency']; ?>',
        'value': productPrice * quantity,
        'items': [{
          'item_id': productId,
          'item_name': productName,
          'price': productPrice,
          'quantity': quantity
        }]
      });

      // Update cart display
      updateCartDisplay(response);
    }
  });
}
</script>

Method 3: Quick Add from Listings

File: product_listing.php or category pages

<!-- For each product in listing -->
<button echo $product['products_id']; ?>', '<?php echo addslashes($product['products_name']); ?>', <?php echo $product['products_price']; ?>)">
  Quick Add
</button>

<script>
function quickAddToCart(productId, productName, productPrice) {
  // Send to cart
  window.location.href = 'shopping_cart.php?action=add_product&products_id=' + productId;

  // Track event
  gtag('event', 'add_to_cart', {
    'currency': '<?php echo $_SESSION['currency']; ?>',
    'value': productPrice,
    'items': [{
      'item_id': productId,
      'item_name': productName,
      'price': productPrice,
      'quantity': 1
    }]
  });
}
</script>

Remove from Cart Tracking

File: shopping_cart.php

Track cart removals:

<?php
// Detect when item is removed
if (isset($_GET['action']) && $_GET['action'] == 'remove_product' && isset($_GET['products_id'])) {
  $products_id = tep_get_prid($_GET['products_id']);

  // Get product info before removal
  if (isset($_SESSION['cart']->contents[$products_id])) {
    $quantity = $_SESSION['cart']->contents[$products_id]['qty'];

    // Get product details for tracking
    $product_query = tep_db_query("SELECT products_name, products_price FROM " . TABLE_PRODUCTS_DESCRIPTION . " pd, " . TABLE_PRODUCTS . " p WHERE pd.products_id = p.products_id AND pd.products_id = '" . (int)$products_id . "' AND pd.language_id = '" . (int)$languages_id . "'");
    $product = tep_db_fetch_array($product_query);
?>
<script>
gtag('event', 'remove_from_cart', {
  'currency': '<?php echo $_SESSION['currency']; ?>',
  'value': <?php echo $product['products_price'] * $quantity; ?>,
  'items': [{
    'item_id': '<?php echo $products_id; ?>',
    'item_name': '<?php echo addslashes($product['products_name']); ?>',
    'price': <?php echo $product['products_price']; ?>,
    'quantity': <?php echo $quantity; ?>
  }]
});
</script>
<?php
  }
}
?>

Cart View Tracking

File: shopping_cart.php

Track when customers view their cart:

<?php
// After cart contents are loaded
if (isset($_SESSION['cart']) && $_SESSION['cart']->count_contents() > 0) {
  $cart_items = array();
  $cart_value = 0;

  $products = $_SESSION['cart']->get_products();
  foreach ($products as $product) {
    $cart_items[] = sprintf(
      '{
        "item_id": "%s",
        "item_name": "%s",
        "price": %s,
        "quantity": %d
      }',
      $product['id'],
      addslashes($product['name']),
      $product['final_price'],
      $product['quantity']
    );
    $cart_value += $product['final_price'] * $product['quantity'];
  }
?>
<script>
gtag('event', 'view_cart', {
  'currency': '<?php echo $_SESSION['currency']; ?>',
  'value': <?php echo $cart_value; ?>,
  'items': [<?php echo implode(',', $cart_items); ?>]
});
</script>
<?php
}
?>

Checkout Initiation Tracking

File: checkout_shipping.php (first checkout page)

<?php
// On checkout page load
if (isset($_SESSION['cart']) && $_SESSION['cart']->count_contents() > 0) {
  $cart_items = array();
  $cart_value = 0;

  $products = $_SESSION['cart']->get_products();
  foreach ($products as $product) {
    $cart_items[] = sprintf(
      '{
        "item_id": "%s",
        "item_name": "%s",
        "price": %s,
        "quantity": %d
      }',
      $product['id'],
      addslashes($product['name']),
      $product['final_price'],
      $product['quantity']
    );
    $cart_value += $product['final_price'] * $product['quantity'];
  }
?>
<script>
gtag('event', 'begin_checkout', {
  'currency': '<?php echo $_SESSION['currency']; ?>',
  'value': <?php echo $cart_value; ?>,
  'items': [<?php echo implode(',', $cart_items); ?>]
});
</script>
<?php
}
?>

Shipping Information Tracking

File: checkout_shipping.php

Track when shipping method is selected:

<script>
// When shipping form submitted
document.querySelector('form[name="checkout_address"]').addEventListener('submit', function() {
  var shippingMethod = document.querySelector('input[name="shipping"]:checked');

  if (shippingMethod) {
    gtag('event', 'add_shipping_info', {
      'currency': '<?php echo $_SESSION['currency']; ?>',
      'value': <?php echo $cart_value; ?>,
      'shipping_tier': shippingMethod.value,
      'items': [<?php echo implode(',', $cart_items); ?>]
    });
  }
});
</script>

Payment Information Tracking

File: checkout_payment.php

Track payment method selection:

<script>
// When payment form submitted
document.querySelector('form[name="checkout_payment"]').addEventListener('submit', function() {
  var paymentMethod = document.querySelector('input[name="payment"]:checked');

  if (paymentMethod) {
    gtag('event', 'add_payment_info', {
      'currency': '<?php echo $_SESSION['currency']; ?>',
      'value': <?php echo $order_total; ?>,
      'payment_type': paymentMethod.value,
      'items': [<?php echo implode(',', $cart_items); ?>]
    });
  }
});
</script>

Purchase Tracking

This is the most critical ecommerce event.

File: checkout_process.php or checkout_success.php

Method 1: Track in checkout_process.php

Add after order is successfully created:

<?php
// After order insertion ($insert_id contains new order_id)
if ($insert_id) {
  // Get order details
  $order_query = tep_db_query("SELECT * FROM " . TABLE_ORDERS . " WHERE orders_id = '" . (int)$insert_id . "'");
  $order = tep_db_fetch_array($order_query);

  // Get order products
  $products_query = tep_db_query("SELECT * FROM " . TABLE_ORDERS_PRODUCTS . " WHERE orders_id = '" . (int)$insert_id . "'");

  $order_items = array();
  while ($product = tep_db_fetch_array($products_query)) {
    $order_items[] = sprintf(
      '{
        "item_id": "%s",
        "item_name": "%s",
        "price": %s,
        "quantity": %d
      }',
      $product['products_id'],
      addslashes($product['products_name']),
      $product['final_price'],
      $product['products_quantity']
    );
  }

  // Get order totals
  $totals_query = tep_db_query("SELECT * FROM " . TABLE_ORDERS_TOTAL . " WHERE orders_id = '" . (int)$insert_id . "'");
  $tax = 0;
  $shipping = 0;

  while ($total = tep_db_fetch_array($totals_query)) {
    if ($total['class'] == 'ot_tax') $tax = $total['value'];
    if ($total['class'] == 'ot_shipping') $shipping = $total['value'];
  }

  // Store tracking data in session for checkout_success.php
  $_SESSION['ga4_purchase'] = array(
    'transaction_id' => $insert_id,
    'value' => $order['order_total'],
    'currency' => $order['currency'],
    'tax' => $tax,
    'shipping' => $shipping,
    'items' => $order_items
  );
}
?>

Method 2: Track in checkout_success.php

File: checkout_success.php

<?php
// Retrieve purchase data from session
if (isset($_SESSION['ga4_purchase'])) {
  $purchase = $_SESSION['ga4_purchase'];
?>
<script>
gtag('event', 'purchase', {
  'transaction_id': '<?php echo $purchase['transaction_id']; ?>',
  'value': <?php echo $purchase['value']; ?>,
  'currency': '<?php echo $purchase['currency']; ?>',
  'tax': <?php echo $purchase['tax']; ?>,
  'shipping': <?php echo $purchase['shipping']; ?>,
  'items': [<?php echo implode(',', $purchase['items']); ?>]
});
</script>
<?php
  // Clear from session to prevent duplicate tracking on refresh
  unset($_SESSION['ga4_purchase']);
}
?>

Prevent Duplicate Purchase Events

Add duplicate prevention:

<?php
// Check if this order was already tracked
if (isset($_SESSION['ga4_tracked_orders'])) {
  $tracked_orders = $_SESSION['ga4_tracked_orders'];
} else {
  $tracked_orders = array();
}

if (!in_array($insert_id, $tracked_orders)) {
  // Track purchase
  // ... tracking code here ...

  // Mark as tracked
  $tracked_orders[] = $insert_id;
  $_SESSION['ga4_tracked_orders'] = $tracked_orders;
}
?>

Coupon/Discount Tracking

File: checkout_payment.php or shopping_cart.php

<?php
// If coupon is applied
if (isset($_SESSION['cc_id'])) {
  $coupon_code = $_SESSION['cc_id'];
  $coupon_query = tep_db_query("SELECT coupon_amount FROM " . TABLE_COUPONS . " WHERE coupon_code = '" . tep_db_input($coupon_code) . "'");
  $coupon = tep_db_fetch_array($coupon_query);
?>
<script>
gtag('event', 'coupon_applied', {
  'coupon': '<?php echo addslashes($coupon_code); ?>',
  'discount': <?php echo $coupon['coupon_amount']; ?>
});
</script>
<?php
}
?>

Refund Tracking (Manual)

OSCommerce doesn't have built-in refund processing, so this must be done manually.

File: admin/orders.php or custom admin page

<?php
// When processing a refund
function processRefund($order_id) {
  // Get order details
  $order_query = tep_db_query("SELECT * FROM " . TABLE_ORDERS . " WHERE orders_id = '" . (int)$order_id . "'");
  $order = tep_db_fetch_array($order_query);

  // Get order products
  $products_query = tep_db_query("SELECT * FROM " . TABLE_ORDERS_PRODUCTS . " WHERE orders_id = '" . (int)$order_id . "'");

  $items = array();
  while ($product = tep_db_fetch_array($products_query)) {
    $items[] = array(
      'item_id' => $product['products_id'],
      'item_name' => $product['products_name'],
      'price' => $product['final_price'],
      'quantity' => $product['products_quantity']
    );
  }

  // Send refund via Measurement Protocol API
  $payload = array(
    'client_id' => $order['customers_id'] ?: 'guest_' . $order_id,
    'events' => array(
      array(
        'name' => 'refund',
        'params' => array(
          'transaction_id' => $order_id,
          'value' => $order['order_total'],
          'currency' => $order['currency'],
          'items' => $items
        )
      )
    )
  );

  // Send to GA4 Measurement Protocol
  $url = 'https://www.google-analytics.com/mp/collect?measurement_id=G-XXXXXXXXXX&api_secret=YOUR_API_SECRET';

  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
  curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  $result = curl_exec($ch);
  curl_close($ch);
}
?>

Multi-Currency Support

OSCommerce supports multiple currencies. Track in user's selected currency:

<?php
// Always use the customer's currency
$currency_code = isset($_SESSION['currency']) ? $_SESSION['currency'] : DEFAULT_CURRENCY;

// When tracking events
?>
<script>
gtag('event', 'purchase', {
  'currency': '<?php echo $currency_code; ?>',
  'value': <?php echo $order_total; ?>,
  // ... other parameters
});
</script>

Testing Ecommerce Tracking

1. Enable Debug Mode

gtag('config', 'G-XXXXXXXXXX', {
  'debug_mode': true
});

2. Complete Test Purchase

  1. Add products to cart
  2. Proceed through checkout
  3. Complete order with test payment
  4. Verify each event in GA4 DebugView

3. Check Event Sequence

Expected flow:

  1. view_item_list (category)
  2. view_item (product page)
  3. add_to_cart
  4. view_cart
  5. begin_checkout
  6. add_shipping_info
  7. add_payment_info
  8. purchase

4. Verify in GA4 Reports

After 24-48 hours:

  • Reports > Monetization > Ecommerce purchases
  • Reports > Monetization > Purchase journey
  • Reports > Monetization > Product performance

Common Issues

Purchase Events Not Tracking

Problem: Order completes but no purchase event

Solutions:

  1. Check order_id is generated correctly
  2. Verify tracking code is in checkout_success.php
  3. Ensure gtag loads before event fires
  4. Check for JavaScript errors
  5. Verify numeric values (not strings)

Duplicate Purchases

Problem: Same order tracked multiple times

Solutions:

  1. Implement session-based duplicate prevention
  2. Clear tracking data after first load
  3. Use cookie to track already-sent orders

Incorrect Revenue

Problem: Revenue doesn't match order total

Solutions:

// Ensure proper numeric formatting
$value = (float)$order['order_total'];  // Cast to float
$value = number_format($value, 2, '.', '');  // Format with period decimal

Currency Issues

Problem: Wrong currency reported

Solutions:

// Always verify currency code
$currency = isset($_SESSION['currency']) ? $_SESSION['currency'] : 'USD';
// Ensure 3-letter ISO code (USD, EUR, GBP, etc.)

Next Steps

Additional Resources