Server-Side Tracking for PrestaShop with GTM and GA4

Standard

Contents:

  1. Introduction to Server-Side Tracking
  2. Required Tools and Setup
  3. Step-by-Step Setup
    • 3.1. Configure GA4
    • 3.2. Set Up GTM Server-Side Container
    • 3.3. Deploy the GTM Server-Side Tagging Server
    • 3.4. Configure PrestaShop to Send Events
    • 3.5. Configure GTM Client and Tags
    • 3.6. Testing and Debugging
  4. Security and Best Practices
  5. Final Thoughts

๐Ÿ” Introduction to Server-Side Tracking

Server-side tracking moves data collection from the client (userโ€™s browser) to a secure server environment. Benefits include:

  • Bypassing ad blockers and browser limitations (e.g., Safari ITP).
  • Enhanced data security and control.
  • Improved site performance.

๐Ÿงฐ Required Tools and Setup

Before you start, make sure you have:

  • A PrestaShop site (v1.7+ recommended).
  • A Google Analytics 4 property.
  • A Google Tag Manager (GTM) account.
  • A server environment for GTM server container, either:
  • Basic knowledge of PHP and server configur

๐Ÿš€ Step-by-Step Setup

3.1. Create and Configure GA4

  1. Go to Google Analytics.
  2. Create a GA4 property.
  3. Set up a Web Data Stream.
  4. Copy the Measurement ID (G-XXXXXXXXXX) for later use.

3.2. Set Up GTM Server-Side Container

  1. In GTM, create a new Server container.
    • Go to GTM Dashboard > Admin > Create Container > Choose “Server”.
  2. Choose a deployment method:
    • App Engine (default and easiest to maintain).
    • Or export the container for manual deployment.
  3. Deploy using Google Cloud:
    • Accept defaults in App Engine setup.
    • Choose a billing account and project.
    • It will provide a server endpoint: https://<your-server>.appspot.com.

3.3. Deploy GTM Server-Side Tagging Server (Alternative: Custom Hosting)
If hosting manually:

Example: Deploying with Docker on VPS

# Clone GTM server image
git clone https://github.com/GoogleCloudPlatform/terraform-google-tag-manager-server.git
cd terraform-google-tag-manager-server

# Configure Docker
docker build -t gtm-server .
docker run -d -p 8080:8080 --name gtm-server gtm-server

Then reverse proxy via Nginx or Apache:

server {
  listen 443 ssl;
  server_name sgtm.example.com;

  location / {
    proxy_pass http://localhost:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }
}

Ensure HTTPS with Letโ€™s Encrypt.

3.4. Configure PrestaShop to Send Events to Server GTM

Hereโ€™s how to send server-side events from PrestaShop using PHP and cURL.

3.4.1. Create a PHP class for GA4 Event Transmission
Create modules/yourmodule/classes/Ga4ServerEvent.php

class Ga4ServerEvent
{
    private $endpoint = 'https://<your-gtm-server>/collect';
    private $measurementId = 'G-XXXXXXXXXX';
    private $apiSecret = 'YOUR_API_SECRET'; // from GA4 Admin > Data Streams > Measurement Protocol

    public function sendEvent($client_id, $event_name, $params = [])
    {
        $payload = [
            'client_id' => $client_id,
            'events' => [
                [
                    'name' => $event_name,
                    'params' => $params
                ]
            ]
        ];

        $url = "https://www.google-analytics.com/mp/collect?measurement_id={$this->measurementId}&api_secret={$this->apiSecret}";

        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($ch);
        curl_close($ch);

        return $response;
    }
}

3.4.2. Hook Into PrestaShop Events

In your moduleโ€™s main file:

public function hookActionOrderStatusPostUpdate($params)
{
    $order = new Order($params['id_order']);
    $customer = new Customer($order->id_customer);
    $client_id = $this->getClientIdFromCookie();

    $eventSender = new Ga4ServerEvent();
    $eventSender->sendEvent($client_id, 'purchase', [
        'currency' => $order->id_currency,
        'value' => $order->total_paid,
        'transaction_id' => $order->reference,
        // Add items array if needed
    ]);
}

private function getClientIdFromCookie()
{
    if (isset($_COOKIE['_ga'])) {
        if (preg_match('/GA\d\.\d\.(\d+\.\d+)/', $_COOKIE['_ga'], $matches)) {
            return $matches[1];
        }
    }
    return uniqid(); // fallback
}

3.5. Configure GTM Server Container

In your Server GTM Container, create a GA4 Client.

  • This processes requests sent from your PrestaShop server.

Add a GA4 Tag to forward data to GA4:

  • Trigger: All requests from the GA4 Client
  • Configure with your GA4 Measurement ID

Optional: Add Filters for Different Events

You can customize by creating triggers for purchase, view_item, etc., and send event data accordingly.

3.6. Test and Debug

  1. Enable Preview Mode in GTM Server container.
  2. Test events by completing a purchase or viewing a product.
  3. Use GA4 DebugView (available in GA4 Admin) to verify events.
  4. Check real-time data in your GA4 dashboard.

4.๐Ÿ›ก๏ธ Security and Best Practices

Restrict Public Access: Use CORS policies or header whitelisting to prevent abuse of your server endpoint.

Log Events: Log requests and responses for troubleshooting.

Use HTTPS: Always encrypt your data in transit.

Set up custom domain: e.g., track.yourdomain.com to improve trust and bypass blockers.

5. ๐Ÿ“˜ Final Thoughts

Server-side tracking with PrestaShop and GA4 ensures data accuracy and long-term resilience. While setup is more complex, the benefits in terms of data integrity, user privacy, and tracking continuity far outweigh the initial configuration overhead.

Mastering Server-Side Tagging in BigCommerce: A Complete Guide to GA4 & Facebook CAPI Integration

Standard

Server-side tagging enhances data privacy, improves data accuracy, and reduces dependency on client-side cookies. For BigCommerce, integrating GA4 and Facebook CAPI server-side requires building a robust tagging infrastructure.

๐Ÿงฑ Architecture

Customer Browser
|
| (1) Data Layer Push
| (2) JS fetch to custom BigCommerce API endpoint (proxy)
v
BigCommerce Custom Endpoint (Frontend)
|
| (3) Forward to GTM Server Container
v
GTM Server Container (App Engine or Cloud Run)
|
|—> Google Analytics 4
|
‘—> Facebook CAPI

๐Ÿ”ง Step 1: Set Up the GTM Server Container

A. Create GTM Server Container

  1. Go to tagmanager.google.com.
  2. Create a new container โ†’ choose Server.
  3. Deploy via App Engine (recommended) or Cloud Run.
  4. Follow Googleโ€™s wizard to deploy:
npx @google-cloud/functions-framework@latest 

B. Set Up Your Custom Domain (Recommended)

  1. Set up a subdomain like gtm.mysite.com.
  2. Update DNS.
  3. Use a managed SSL certificate.

๐Ÿ›๏ธ Step 2: Create BigCommerce Proxy Endpoint

Why?

BigCommerce doesnโ€™t allow direct server-side logic. So, use Stencil theme customization + a lightweight proxy API (e.g., Cloud Function or Lambda) to forward events from browser to GTM server.

A. Frontend JS: Capture Events

In your BigCommerce theme (templates/layout/base.html):

<script>
  window.dataLayer = window.dataLayer || [];

  function sendEventToServer(event) {
    fetch('https://your-api-proxy.com/track-event', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(event)
    });
  }

  // Example: Purchase Event
  document.addEventListener("DOMContentLoaded", function () {
    const orderData = {{checkout.order|json}};
    const event = {
      event_name: "purchase",
      currency: orderData.currency.code,
      value: orderData.order_amount,
      transaction_id: orderData.id,
      user_data: {
        email: orderData.customer.email
      },
      items: orderData.items.map(item => ({
        item_name: item.name,
        item_id: item.product_id,
        price: item.price_inc_tax,
        quantity: item.quantity
      }))
    };

    sendEventToServer(event);
  });
</script>

โ˜๏ธ Step 3: Deploy the Proxy (Cloud Function Example)

Create an endpoint that forwards events to GTM Server.

// index.js

const fetch = require('node-fetch');

exports.trackEvent = async (req, res) => {
  const event = req.body;
  const GTM_SERVER_URL = 'https://gtm.mysite.com/collect';

  try {
    await fetch(GTM_SERVER_URL, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-gtm-server': 'true'
      },
      body: JSON.stringify(event)
    });

    res.status(200).send({ success: true });
  } catch (e) {
    console.error(e);
    res.status(500).send({ error: 'Failed to forward event' });
  }
};

๐Ÿท๏ธ Step 4: Configure GTM Server Container

A. Create Custom GA4 Tag (Server-Side)

  1. Open GTM Server Container.
  2. Add new GA4 Tag.
  3. Use event parameters from the payload.
  4. Set Measurement ID.

B. Facebook CAPI Tag

Use the official Facebook Conversion API Template in GTM server.

Setup Steps:

  1. Go to Templates โ†’ Add Community Template โ†’ Search โ€œFacebook Conversion APIโ€.
  2. Configure:
    • Pixel ID
    • Access Token
    • Event Name
    • User Data (email, IP, user agent)
  3. Set up triggers based on event name (e.g., purchase).

๐Ÿ” Step 5: Facebook Access Token & Pixel Setup

  1. Go to Facebook Events Manager.
  2. Create Pixel โ†’ Click โ€œConversions APIโ€ setup.
  3. Generate Access Token.
  4. Add to GTM Server Tag.

๐Ÿ“Š Step 6: Test and Validate

A. GTM Server Container Debug Mode

  • Use Preview in GTM server.
  • Send test events via your proxy.

B. Facebook Test Events

  • Go to Events Manager โ†’ Select Pixel โ†’ Test Events.
  • Confirm your CAPI events are received.

C. GA4 Realtime

  • View events in Realtime under GA4.
  • Use event_name filtering for confirmation.

โœ… Bonus: Advanced Features

1. Email Hashing (SHA256 for Facebook)

Facebook requires hashed PII. Add this logic in your proxy:

const crypto = require('crypto');

function hashEmail(email) {
  return crypto.createHash('sha256').update(email.trim().toLowerCase()).digest('hex');
}

2. IP Address Forwarding

If you’re using Cloudflare or another proxy, make sure req.ip is forwarded via headers like x-forwarded-for.

๐Ÿ” Troubleshooting Tips

IssueSolution
CAPI Events not receivedCheck access token, pixel ID, user data fields
GA4 Missing EventsValidate GTM server client config and measurement ID
GTM Server not reachableConfirm DNS, SSL setup, and firewall rules

๐Ÿง  Conclusion

Implementing server-side tagging for BigCommerce with GA4 and Facebook CAPI provides better control, higher data accuracy, and improved privacy compliance. With GTM Server Container at the core, you create a future-proof, secure data pipeline.

๐Ÿ”งImplementing Server-Side Google Analytics 4 & Meta Pixel Tracking in Magento 2 for Accurate, Privacy-Ready E-commerce Data

Standard

ย 

Server-side tracking is essential in a world increasingly focused on data privacy, ad blockers, and iOS limitations. Relying solely on client-side tracking (JavaScript in browsers) can lead to data loss.

๐Ÿง  Why Use Server-Side Tracking?

Accuracy: Bypasses ad blockers and browser restrictions.

Resilience: Maintains data integrity even with JavaScript disabled.

Compliance: Easier to comply with GDPR/CCPA by controlling data flow.

Performance: Reduces front-end JavaScript overhead.

๐Ÿ—๏ธ Architecture Overview

Magento 2 โ†’ Custom Observer (Order Placed) โ†’ Server-Side Controller/Service โ†’ GA4 & Meta Conversion API

Part 1: Magento 2 Custom Module Setup

๐Ÿ“ 1.1 Create the Module Directory Structure

app/code/Custom/ServerSideTracking/
โ”œโ”€โ”€ registration.php
โ”œโ”€โ”€ etc/module.xml
โ”œโ”€โ”€ etc/events.xml
โ”œโ”€โ”€ Observer/OrderSuccessObserver.php
โ”œโ”€โ”€ Helper/TrackingHelper.php
โ”œโ”€โ”€ Model/GA4Service.php
โ”œโ”€โ”€ Model/MetaPixelService.php

๐Ÿงฉ 1.2 Module Files

registration.php

ย 


<?php
use Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Custom_ServerSideTracking', __DIR__);

etc/module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Custom_ServerSideTracking" setup_version="1.0.0"/>
</config>

Part 2: Order Observer

etc/events.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="checkout_onepage_controller_success_action">
        <observer name="custom_serversidetracking_order_success" instance="Custom\ServerSideTracking\Observer\OrderSuccessObserver"/>
    </event>
</config>

Observer/OrderSuccessObserver.php

<?php
namespace Custom\ServerSideTracking\Observer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Sales\Model\OrderFactory;
use Custom\ServerSideTracking\Model\GA4Service;
use Custom\ServerSideTracking\Model\MetaPixelService;

class OrderSuccessObserver implements ObserverInterface
{
    protected $orderFactory;
    protected $ga4Service;
    protected $metaPixelService;

    public function __construct(
        OrderFactory $orderFactory,
        GA4Service $ga4Service,
        MetaPixelService $metaPixelService
    ) {
        $this->orderFactory = $orderFactory;
        $this->ga4Service = $ga4Service;
        $this->metaPixelService = $metaPixelService;
    }

    public function execute(Observer $observer)
    {
        $orderIds = $observer->getEvent()->getOrderIds();
        if (!is_array($orderIds)) return;

        foreach ($orderIds as $orderId) {
            $order = $this->orderFactory->create()->load($orderId);
            $this->ga4Service->sendPurchaseEvent($order);
            $this->metaPixelService->sendPurchaseEvent($order);
        }
    }
}

Part 3: Google Analytics 4 Server-Side (Measurement Protocol)

Model/GA4Service.php

<?php
namespace Custom\ServerSideTracking\Model;

use Magento\Sales\Model\Order;

class GA4Service
{
    protected $measurementId = 'G-XXXXXXXXXX';
    protected $apiSecret = 'YOUR_API_SECRET';

    public function sendPurchaseEvent(Order $order)
    {
        $url = "https://www.google-analytics.com/mp/collect?measurement_id={$this->measurementId}&api_secret={$this->apiSecret}";

        $clientId = md5($order->getCustomerEmail()); // You can make this more robust

        $products = [];
        foreach ($order->getAllVisibleItems() as $item) {
            $products[] = [
                'item_id' => $item->getSku(),
                'item_name' => $item->getName(),
                'quantity' => (int) $item->getQtyOrdered(),
                'price' => (float) $item->getPrice()
            ];
        }

        $payload = [
            'client_id' => $clientId,
            'events' => [[
                'name' => 'purchase',
                'params' => [
                    'transaction_id' => $order->getIncrementId(),
                    'currency' => $order->getOrderCurrencyCode(),
                    'value' => (float) $order->getGrandTotal(),
                    'items' => $products
                ]
            ]]
        ];

        $this->sendRequest($url, $payload);
    }

    protected function sendRequest($url, $payload)
    {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
            CURLOPT_POSTFIELDS => json_encode($payload)
        ]);
        curl_exec($ch);
        curl_close($ch);
    }
}

Part 4: Meta (Facebook) Conversion API

Model/MetaPixelService.php

<?php
namespace Custom\ServerSideTracking\Model;

use Magento\Sales\Model\Order;

class MetaPixelService
{
    protected $accessToken = 'YOUR_META_ACCESS_TOKEN';
    protected $pixelId = 'YOUR_PIXEL_ID';

    public function sendPurchaseEvent(Order $order)
    {
        $url = "https://graph.facebook.com/v18.0/{$this->pixelId}/events?access_token={$this->accessToken}";

        $eventId = uniqid('order_');
        $userData = [
            'em' => [hash('sha256', strtolower(trim($order->getCustomerEmail())))],
        ];

        $contents = [];
        foreach ($order->getAllVisibleItems() as $item) {
            $contents[] = [
                'id' => $item->getSku(),
                'quantity' => (int) $item->getQtyOrdered(),
                'item_price' => (float) $item->getPrice()
            ];
        }

        $eventData = [
            'event_name' => 'Purchase',
            'event_time' => time(),
            'event_id' => $eventId,
            'user_data' => $userData,
            'custom_data' => [
                'currency' => $order->getOrderCurrencyCode(),
                'value' => (float) $order->getGrandTotal(),
                'contents' => $contents,
                'content_type' => 'product'
            ]
        ];

        $payload = ['data' => [$eventData]];

        $this->sendRequest($url, $payload);
    }

    protected function sendRequest($url, $payload)
    {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
            CURLOPT_POSTFIELDS => json_encode($payload)
        ]);
        curl_exec($ch);
        curl_close($ch);
    }
}

โœ… Testing & Validation

  1. Use tools like Google Tag Assistant and Meta Events Manager.
  2. Check server logs for errors (enable debug logging in your helper).
  3. Validate data using tools:

๐Ÿ“Œ Tips & Best Practices

  • Ensure GDPR Compliance: Send data only with consent.
  • Throttle Requests: Avoid spamming APIs (especially Meta).
  • Security: Hide secrets (e.g., use env.php to store tokens).
  • Track More Events: Add add_to_cart, view_item, etc., as needed.

๐Ÿ”š Conclusion

By integrating server-side tracking for Google Analytics and Meta Pixel in Magento 2, you significantly increase data accuracy, bypass client-side blockers, and align better with modern privacy requirements. This approach lays the foundation for advanced tracking and better marketing attribution.

Boost WooCommerce Accuracy: Implement GA4 Server-Side Tracking with PHP

Standard

With rising browser restrictions and ad blockers, server-side tracking is becoming crucial for reliable analytics.

๐Ÿ”ง Why Use Server-Side Tracking on WooCommerce?

  • Improves Data Accuracy: Bypasses ad blockers and browser restrictions.
  • Better Attribution: Tracks conversions more accurately.
  • Data Control: You control data routing and filtering.
  • Security: Reduces exposure of measurement IDs and secrets.

๐Ÿ” How Server-Side GA4 Works

  • WooCommerce triggers events (purchase, add to cart, etc.)
  • These events are captured server-side (e.g., PHP backend).
  • Data is sent to a server endpoint (e.g., Google Tag Manager Server or direct to GA4 via Measurement Protocol).

๐Ÿงฐ Prerequisites

  • GA4 Property
  • WooCommerce (WordPress) admin access
  • PHP 7.4+
  • Access to deploy server-side tagging (recommended: Google Cloud with GTM SS container)
  • Your GA4 Measurement ID and API Secret (found in Admin > Data Streams > Measurement Protocol API)

โœ… Step-by-Step Implementation

1. Set Up GTM Server-Side Container

  • Go to tagmanager.google.com โ†’ Create a Server container.
  • Deploy container via Google App Engine (recommended) or custom endpoint.
  • Note your server URL (e.g., https://gtm.yourdomain.com).

2. Configure GA4 Client in GTM SS

  • Inside your server container, go to Clients โ†’ Add a new client โ†’ Choose GA4.
  • This client listens to incoming GA4 requests.

3.Create GA4 Measurement Protocol Endpoint

  • If youโ€™re not using GTM Server, send requests directly to:

https://www.google-analytics.com/mp/collect?measurement_id=G-XXXXXXX&api_secret=YOUR_SECRET

4. WooCommerce PHP Code: Capture Purchase Data

  • Place this in your theme’s functions.php or a custom plugin:

add_action('woocommerce_thankyou', 'send_server_side_ga4_purchase', 10, 1);
function send_server_side_ga4_purchase($order_id) {
if (!$order_id) return;

$order = wc_get_order($order_id);
$ga_measurement_id = 'G-XXXXXXX';
$ga_api_secret = 'YOUR_SECRET';

$client_id = $_COOKIE['_ga'] ?? '555.999'; // fallback if _ga missing
preg_match('/GA1\.1\.(\d+\.\d+)/', $client_id, $matches);
$client_id_parsed = $matches[1] ?? $client_id;

$items = [];
foreach ($order->get_items() as $item) {
$product = $item->get_product();
$items[] = [
'item_id' => $product->get_id(),
'item_name' => $item->get_name(),
'price' => $order->get_line_subtotal($item, true),
'quantity' => $item->get_quantity()
];
}

$payload = [
'client_id' => $client_id_parsed,
'events' => [[
'name' => 'purchase',
'params' => [
'transaction_id' => $order->get_order_number(),
'value' => $order->get_total(),
'currency' => $order->get_currency(),
'items' => $items
]
]]
];

$endpoint = "https://www.google-analytics.com/mp/collect?measurement_id=$ga_measurement_id&api_secret=$ga_api_secret";

$args = [
'headers' => ['Content-Type' => 'application/json'],
'body' => wp_json_encode($payload),
'timeout' => 20
];

wp_remote_post($endpoint, $args);
}


    ๐Ÿ”’ Best Practices

        • Use GTM Server endpoint instead of google-analytics.com for more control.
        • Log failed requests for debugging.
        • Hash or encrypt user IDs if sending PII.
        • Combine with client-side GA4 for a hybrid approach.

    ๐Ÿ” Debugging Tips

        • Check Network tab for mp/collect status.
        • Use GA4โ€™s DebugView by adding ?debug_mode=1 to the payload.
        • Log responses using error_log() in WordPress if needed.

    โœ… Validation

    Use GA4 DebugView:

        • Go to Admin > DebugView
        • Send a test purchase
        • Confirm the purchase event and parameters show up.

    ๐Ÿ“Š Bonus: Add More WooCommerce Events

    Extend tracking for:

        • add_to_cart
        • begin_checkout
        • view_item
        • login or sign_up

    Use hooks like:

      <!-- wp:heading -->
      <h2 class="wp-block-heading"></h2>
      <!-- /wp:heading -->

      ๐Ÿš€ Wrapping Up

      Implementing server-side GA4 tracking for WooCommerce boosts data integrity and future-proofs your analytics. With accurate purchase data, better attribution, and reduced client-side dependency, your marketing insights will thrive.