With privacy regulations like GDPR, CCPA, and browser changes (e.g., Safariβs ITP, Firefox ETP), traditional client-side tracking is no longer reliable. Users block cookies, disable JavaScript, or opt out of tracking entirely.
Server-side tracking provides a robust, privacy-conscious solution to improve attribution, ensure compliance, and deliver high-quality data across GA4, Google Ads, Meta CAPI, and other platforms.
π― Goals of Server-Side Tracking
- Restore conversion attribution even when client-side is blocked
- Respect consent while improving data fidelity
- Maintain ad platform visibility (Google Ads, Meta Ads)
- Enable first-party data enrichment and modeling
π§° Requirements
- A deployed Server-Side GTM container (
gtm.yourdomain.com
) - GA4 and Google Ads accounts
- Consent management platform (CMP) or custom consent system
- Web GTM container installed on site
- OpenCart (or any other eCommerce platform) with customization access
π Step-by-Step Guide
πΉ Step 1: Deploy Your Server-Side GTM Container
Use Google Cloud App Engine or a provider like Stape.io:
https://github.com/GoogleCloudPlatform/terraform-google-tag-manager
Example endpoint:https://gtm.yourdomain.com
β Set this domain as a first-party cookie server for better attribution.
πΉ Step 2: Update GA4 and Conversion Tags to Use Transport URL
In Web GTM:
- Modify your GA4 Configuration tag:
- Add field:
transport_url
=https://gtm.yourdomain.com
- Add field:
- Modify Google Ads / Meta tags to also send data server-side (if applicable)
β This routes tracking data through your server endpoint.
πΉ Step 3: Setup Consent-Aware Data Collection
Ensure that user consent is respected before sending data to the server:
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: "default_consent",
ad_storage: "denied",
analytics_storage: "denied"
});
// After consent given
function onConsentGranted() {
dataLayer.push({
event: "update_consent",
ad_storage: "granted",
analytics_storage: "granted"
});
}
β Integrate with your CMP (e.g., Cookiebot, OneTrust) to update consent dynamically.
πΉ Step 4: Capture User Identifiers (GCLID, FBC, Client_ID)
Use JS to extract and store first-party identifiers:
<script>
(function(){
const urlParams = new URLSearchParams(window.location.search);
const gclid = urlParams.get('gclid');
const fbc = urlParams.get('fbclid');
if (gclid) document.cookie = `gclid=${gclid}; path=/; max-age=2592000; SameSite=Lax`;
if (fbc) document.cookie = `fbc=${fbc}; path=/; max-age=2592000; SameSite=Lax`;
})();
</script>
β These cookies are used server-side to match sessions with ad clicks.
πΉ Step 5: Send Conversion Events from Client to Server
Example purchase
push (in success.twig
):
<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
event: 'purchase',
ecommerce: {
transaction_id: '{{ order_id }}',
value: '{{ total }}',
currency: '{{ currency }}',
items: [
{% for product in products %}
{
item_id: '{{ product.model }}',
item_name: '{{ product.name|escape('js') }}',
price: '{{ product.price }}',
quantity: '{{ product.quantity }}'
}{% if not loop.last %},{% endif %}
{% endfor %}
]
},
user_data: {
email: '{{ customer.email|lower|sha256 }}',
phone: '{{ customer.telephone|sha256 }}',
client_id: '{{ ga_client_id }}',
gclid: '{{ gclid_cookie }}',
fbc: '{{ fbc_cookie }}'
},
event_id: 'oc_{{ order_id }}'
});
</script>
β Use SHA256 hashing in PHP or JS for PII (email, phone) before pushing.
πΉ Step 6: Handle Events in Server GTM
In Server-Side GTM:
- Create Variables:
ecommerce.value
user_data.email
event_id
- Create Tags:
- GA4 Server Tag β Sends to GA4
- Google Ads Conversion Tag β Sends to Google Ads
- Meta CAPI Tag (via HTTP Request Tag or Template)
Trigger Condition:Event Name equals "purchase"
and Consent granted = true
πΉ Step 7: Add HTTP Headers for Attribution Enrichment
Enable Request Headers
in server GTM to read:
User-Agent
IP Address
Referer
β This enhances matching accuracy in Meta, GA4, and Google Ads.
πΉ Step 8: Implement Conversion Deduplication
In all purchase
events, include:
"event_id": "oc_{{order_id}}"
In server-side tags (Google Ads, GA4, Meta), map event_id
so platforms can deduplicate conversions from multiple sources (e.g., client + server).
π§ͺ QA Checklist
Item | β |
---|---|
GA4 uses transport_url |
β |
Event sent from client to server | β |
Server GTM receives and processes | β |
Consent checked before firing | β |
event_id used for deduplication | β |
Headers available in request | β |
Matching identifiers present (gclid, client_id) | β |
π§ Pro Tips
Tip | Why It Matters |
---|---|
Use hashed PII for privacy | Enables matching without storing raw data |
Set up logging in Server GTM | Audit conversion flow |
Whitelist trusted domains | Prevent spoofed requests |
Monitor via GA4 DebugView + GTM Server Preview | Real-time validation |
Always fallback to client-only if user denies consent | Legal compliance |
π¦ Architecture Summary
[Client Browser]
β
[dataLayer β Web GTM]
β β
[Consent Check] [GA4 Tag β transport_url=https://gtm.yourdomain.com]
β
[Server-Side GTM Container]
β β β
[GA4] [Google Ads] [Meta CAPI]