GA4 Ecommerce Data Layer Bridge
In this article we will create a translation script that takes your websites window.dataLayer
(GTM Data Layer) and translates ecommerce events with GA4 data models (https://developers.google.com/analytics/devguides/collection/ga4/ecommerce?hl=en&client_type=gtm) into the JENTIS native data layer. Creating a fast and easy solution to get started without the need to change your website.
The Why and The Mission
In the realm of digital analytics, Google Analytics 4 (GA4) stands out as a popular tool for tracking and analyzing user behavior. Its enhanced capabilities, particularly in the realm of ecommerce tracking, provide invaluable insights for businesses striving to understand their customers better. However, the native data model of GA4 might not always align perfectly with your specific needs or existing infrastructure.
For those leveraging tag management solutions like Google Tag Manager (GTM), transitioning from the familiar dataLayer format to a new data model can sometimes be a daunting task. This is where our custom code solution comes into play, offering a seamless bridge between your existing dataLayer and GA4's ecommerce data model.
Purpose/Goal: The primary objective of our approach is to simplify the process of integrating ecommerce tracking with JENTIS into your website, without requiring significant overhauls or modifications to your existing data infrastructure. By leveraging our solution, you can continue utilizing your current dataLayer implementation while seamlessly translating the data into our uniform and toolagnostic format, represented by our custom data layer convention (JENTIS Data Layer: Push Data ).
This approach not only streamlines the implementation process but also ensures consistency and accuracy in tracking ecommerce events, ultimately empowering businesses to make data-driven decisions with confidence.
Key Benefits and Features:
Seamless Integration: Our solution seamlessly integrates with your existing dataLayer structure, eliminating the need for extensive redevelopment or restructuring.
Familiar Tag Management Workflow: By mimicking the familiar push mechanism utilized in GTM and GA4, our solution ensures a smooth transition for users accustomed to these workflows.
Benefit from Default Settings: All our tools, tags, trigger and variables we provide out of the box in the JENTIS Data Capturing Platform work automatically. Creating less friction in the configuration.
Toolagnostic Approach: While other tools like GA4 and GTM create a data model specific to a single tool (and hence you must translate to other tools like Facebook Conversion API, etc.) we do the heavy lifting for you. The tool independent approach we take with our data layer scales with each tool you add.
How It Works: At its core, this coding solution functions as a translating code that intercepts the data pushed to the existing dataLayer and translates it into the format expected by our ecommerce data model (Ecommerce Tracking ). This translation process occurs seamlessly in the background, without disrupting the flow of data or user experience on your website.
Upon implementation, our solution essentially acts as a middleware, bridging the gap between your current dataLayer structure and GA4's requirements. This ensures that crucial ecommerce events such as product views, adds to cart, purchases, and more are accurately tracked and reported within GA4, empowering you with comprehensive insights into user behavior and purchasing patterns.
Drawbacks and Pitfalls
While our tag management solution offers a streamlined approach to integrating GA4 ecommerce tracking, it's essential to acknowledge potential drawbacks and pitfalls to make informed decisions about a bridging code implementation.
Implementing a bridge code solution is never the best practice or a solution that some should aim for. As a native integration of our JENTIS data layer would be more resilient and performant. So make sure to check this section for possible pitfalls and caveats.
Secret Dependency: To most website developers that provide the original
window.dataLayer
it might be logical to assume that if GTM is gone the dataLayer might not be required any more. That this bridging code approach creates a dependency is possibly not known to your website development department - this make this approach error prone.Data Consistency Challenges: Despite our best efforts to maintain data integrity, the translation process introduces an additional layer of complexity. Any discrepancies or inconsistencies between the original dataLayer format and the translated _jts format could potentially impact the accuracy of the reported metrics in GA4.
Limited Customization Flexibility: While our solution offers customization options, it may not cater to every unique requirement or scenario. Businesses with highly specialized tracking needs or complex data structures may find it challenging to adapt our solution to fit their specific use cases effectively.
Performance Overhead: Introducing additional code for the translation process may impose a slight performance overhead on the website. While we strive to minimize this impact, it's essential to conduct thorough testing to ensure that the integration does not adversely affect page load times or user experience.
Maintenance and Updates: As GA4 evolves and introduces new features or changes to its data model, our solution may require updates to remain compatible and effective. This necessitates ongoing maintenance and monitoring to ensure continued accuracy and functionality.
Risk of Data Loss or Corruption: Any errors or misconfigurations in the translation process could potentially lead to data loss or corruption. It's crucial to implement thorough error handling mechanisms and conduct regular audits to mitigate this risk.
Complexity of Troubleshooting: Debugging issues related to the translation process may be more complex compared to traditional implementations. Identifying and resolving discrepancies between the original dataLayer and the translated _jts format may require specialized expertise and troubleshooting techniques.
Implementing the Custom Code
Now with the motivation and possible drawbacks considered let’s run through the implementation.
The following events and properties will be mapped from the original GA4 ecommerce data model to the JENTIS ecommerce data model.
Event Mappings
The following events are mapped with this approach:
"view_item_list" = "productlist";
"select_item" = "productlistclick";
"view_item" = "productview";
"add_to_wishlist" = "addtowishlist";
"add_to_cart" = "addtocart";
"remove_from_cart" = "removefromcart";
"view_cart" = "cartview";
"begin_checkout" = "checkout";
"add_shipping_info" = "checkout";
"add_payment_info" = "checkout";
"refund" = "refund";
"purchase" = "order";
"view_promotion" = "promotionimpression";
"select_promotion" = "promotionclick";
default (if mapping fails): "jtm_customcode_mapping_failed";
The event name (ie. “view_item_list”) maps to the product.type property in JENTIS. Further an according _jts.push(track:'productlist'); is tracked with this mapping.
Property Mappings
Each item property translates into a product attribute. Here is the mapping:
"track" : "product",
"type" : "", //based on event mapping
"id" : item.item_id,
"name" : item.item_name,
"group" : [
item.item_category,
item.item_category2,
item.item_category3,
item.item_category4,
item.item_category5
],
"variant" : item.item_variant,
"quantity" : item.quantity,
"brutto" : item.price && item.discount ? item.price - item.discount : item.price,
"discount" : item.discount,
"position" : item.index,
"oldbrutto" : item.price,
"brand" : item.item_brand
Creating the Custom Code in JENTIS Tag Manager
To add this translation script to your JENTIS Tag Manager account please navigate to “JENTIS Tag Manager: Codes” section.
There add a new code element. For the settings give it a good name and select the containers, where you want this translation to apply.
Copy paste this code to the JS Code input field of that element:
// Step 1: Ensure the existence of both dataLayer arrays
window.dataLayer = window.dataLayer || [];
window._jts = window._jts || [];
// Step 2: Intercept push calls to window.dataLayer
(function(originalPush) {
window.dataLayer.push = function() {
// Convert arguments to a real array to work with
var args = Array.prototype.slice.call(arguments);
// Process each object being pushed
for (var i = 0; i < args.length; i++) {
try{
var obj = args[i];
// Step 3: Process and transform the intercepted data
var jtsPushCommands = transformDataLayerObject(obj);
// Step 4: Forward the transformed data to window._jts
for(var j = 0; j < jtsPushCommands.length; j++){
window._jts.push(jtsPushCommands[j]);
}
}catch(e){
console.warn("JENTIS GA4 DataLayer BRIDGE FAILED");
}
}
// Continue with the normal dataLayer push process
originalPush.apply(window.dataLayer, arguments);
};
})(window.dataLayer.push);
function itemToProductMapping(item, jtsType){
return {
"track" : "product",
"type" : jtsType,
"id" : item.item_id,
"name" : item.item_name,
"group" : [
item.item_category,
item.item_category2,
item.item_category3,
item.item_category4,
item.item_category5
],
"variant" : item.item_variant,
"quantity" : item.quantity,
"brutto" : item.price && item.discount ? item.price - item.discount : item.price,
"discount" : item.discount,
"position" : item.index,
"oldbrutto" : item.price,
"brand" : item.item_brand,
"coupon" : item.coupon
};
}
function ecommerceToDocumentMapping(ecomm, event){
var jtsTrack = "";
switch(event) {
case "view_item_list":
jtsTrack = "productlist";
break;
case "select_item":
jtsTrack = "productlistclick";
break;
case "view_item":
jtsTrack = "productview";
break;
case "add_to_wishlist":
jtsTrack = "addtowishlist";
break;
case "add_to_cart":
jtsTrack = "addtocart";
break;
case "remove_from_cart":
jtsTrack = "removefromcart";
break;
case "view_cart":
jtsTrack = "cartview";
break;
case "begin_checkout":
jtsTrack = "checkout";
break;
case "add_shipping_info":
jtsTrack = "checkout";
break;
case "add_payment_info":
jtsTrack = "checkout";
break;
case "refund":
jtsTrack = "refund";
break;
case "purchase":
jtsTrack = "order";
break;
case "view_promotion":
jtsTrack = "promotionimpression";
break;
case "select_promotion":
jtsTrack = "promotionclick";
break;
default:
jtsTrack = "jtm_customcode_mapping_failed";
}
var jtsDoc = {
track: jtsTrack
};
if(jtsTrack == "checkout"){
switch(event) {
case "begin_checkout":
jtsDoc.step = "1";
break;
case "add_payment_info":
jtsDoc.step = "2";
break;
case "add_shipping_info":
jtsDoc.step = "3";
break;
}
}
if(ecomm.item_list_id)
jtsDoc.id = ecomm.item_list_id;
if(ecomm.item_list_name)
jtsDoc.name = ecomm.item_list_name;
if(ecomm.currency)
jtsDoc.currency = ecomm.currency;
if(ecomm.value)
jtsDoc.value = ecomm.value;
if(ecomm.shipping_tier)
jtsDoc.shipping_tier = ecomm.shipping_tier;
if(ecomm.payment_type)
jtsDoc.paytype = ecomm.payment_type;
if(ecomm.transaction_id)
jtsDoc.orderid = ecomm.transaction_id;
if(ecomm.tax)
jtsDoc.tax = ecomm.tax;
if(ecomm.shipping)
jtsDoc.shipping = ecomm.shipping;
if(ecomm.coupon)
jtsDoc.vouchers = [{"code":ecomm.coupon}];
if(jtsTrack == "order")
jtsDoc.brutto = ecomm.value;
return jtsDoc;
}
// Function to transform dataLayer object
function transformDataLayerObject(obj) {
var jtsCommands = [];
if(obj.ecommerce && obj.event){
var jtsDocument = ecommerceToDocumentMapping(obj.ecommerce, obj.event);
if(Array.isArray(obj.ecommerce.items)) {
// Process each product item
obj.ecommerce.items.forEach(function(item) {
// Transform each product into the required format and push to _jts
var transformedProduct = itemToProductMapping(item, jtsDocument.track);
// Push the transformed product to _jts
jtsCommands.push(transformedProduct);
});
}
jtsCommands.push(jtsDocument);
if(obj.event == "view_promotion" || obj.event == "select_promotion"){
var jtsPromo = {
track : "promotion",
id : obj.ecommerce.promotion_id,
name : obj.ecommerce.promotion_name,
creative : obj.ecommerce.creative_name,
creativeslow : obj.ecommerce.creative_slot
}
jtsPromo.type = obj.event == "view_promotion" ? "promotionimpression" : "promotionclick";
jtsCommands.push(jtsPromo);
jtsCommands.push({track:jtsPromo.type});
}
jtsCommands.push({track:"submit"});
}
return jtsCommands;
}
// Step 5: Handle existing data in window.dataLayer
// Process each existing object in dataLayer
window.dataLayer.forEach(function(obj) {
var jtsPushCommands = transformDataLayerObject(obj);
for(var j = 0; j < jtsPushCommands.length; j++){
window._jts.push(jtsPushCommands[j]);
}
});
Conclusion
In conclusion, our tag management solution offers a straightforward and efficient approach to integrate GA4 ecommerce tracking into your website without adding a new data layer to it. By maintaining compatibility with your existing data infrastructure and simplifying the translation process, we aim to empower businesses with the insights they need to thrive in today's digital landscape.
With our solution, you can seamlessly leverage the advanced capabilities of GA4 without the hassle of extensive redevelopment or restructuring. Embrace the power of data-driven decision-making and unlock new opportunities for growth with our simplified approach to Google Analytics 4 ecommerce tracking.