From 1cd142ae5dec83caeb5f12549a3c2a06cefe2c9f Mon Sep 17 00:00:00 2001 From: Mo Mustafa Date: Fri, 1 Mar 2024 12:05:56 -0800 Subject: [PATCH 1/5] fix: include measurement Id as event param --- packages/GA4Client/src/commerce-handler.js | 255 +++++++++++---------- packages/GA4Client/src/event-handler.js | 5 + 2 files changed, 144 insertions(+), 116 deletions(-) diff --git a/packages/GA4Client/src/commerce-handler.js b/packages/GA4Client/src/commerce-handler.js index 2356e99..15c407a 100644 --- a/packages/GA4Client/src/commerce-handler.js +++ b/packages/GA4Client/src/commerce-handler.js @@ -54,18 +54,18 @@ CommerceHandler.prototype.logCommerceEvent = function (event) { event.CustomFlags[GA4_COMMERCE_EVENT_TYPE] === VIEW_CART ) { isViewCartEvent = true; - return logViewCart(event, affiliation); + return this.logViewCart(event, affiliation); } } // Handle Impressions if (event.EventCategory === ProductActionTypes.Impression) { - return logImpressionEvent(event, affiliation); + return this.logImpressionEvent(event, affiliation); // Handle Promotions } else if ( event.EventCategory === PromotionActionTypes.PromotionClick || event.EventCategory === PromotionActionTypes.PromotionView ) { - return logPromotionEvent(event); + return this.logPromotionEvent(event); } switch (event.EventCategory) { @@ -99,7 +99,7 @@ CommerceHandler.prototype.logCommerceEvent = function (event) { break; case ProductActionTypes.CheckoutOption: - return logCheckoutOptionEvent(event, affiliation); + return this.logCheckoutOptionEvent(event, affiliation); default: // a view cart event is handled at the beginning of this function @@ -136,10 +136,144 @@ CommerceHandler.prototype.logCommerceEvent = function (event) { null; } - gtag('event', mapGA4EcommerceEventName(event), ga4CommerceEventParameters); + this.sendCommerceEventToGA4( + mapGA4EcommerceEventName(event), + ga4CommerceEventParameters + ); return true; }; +CommerceHandler.prototype.sendCommerceEventToGA4 = function ( + eventName, + eventAttributes +) { + if (this.common.forwarderSettings.measurementId) { + eventAttributes.send_to = this.common.forwarderSettings.measurementId; + } + + gtag('event', eventName, eventAttributes); +}; + +// Google previously had a CheckoutOption event, and now this has been split into 2 GA4 events - add_shipping_info and add_payment_info +// Since MP still uses CheckoutOption, we must map this to the 2 events using custom flags. To prevent any data loss from customers +// migrating from UA to GA4, we will set a default `set_checkout_option` which matches Firebase's data model. +CommerceHandler.prototype.logCheckoutOptionEvent = function ( + event, + affiliation +) { + try { + var customFlags = event.CustomFlags, + GA4CommerceEventType = customFlags[GA4_COMMERCE_EVENT_TYPE], + ga4CommerceEventParameters; + + // if no custom flags exist or there is no GA4CommerceEventType, the user has not updated their code from using legacy GA which still supports checkout_option + if (!customFlags || !GA4CommerceEventType) { + console.error( + 'Your checkout option event for the Google Analytics 4 integration is missing a custom flag for "GA4.CommerceEventType". The event was sent using the deprecated set_checkout_option event. Review mParticle docs for GA4 for the custom flags to add.' + ); + } + + switch (GA4CommerceEventType) { + case ADD_SHIPPING_INFO: + ga4CommerceEventParameters = buildAddShippingInfo( + event, + affiliation + ); + break; + case ADD_PAYMENT_INFO: + ga4CommerceEventParameters = buildAddPaymentInfo( + event, + affiliation + ); + break; + default: + ga4CommerceEventParameters = buildCheckoutOptions( + event, + affiliation + ); + break; + } + } catch (error) { + console.error( + 'There is an issue with the custom flags in your CheckoutOption event. The event was not sent. Plrease review the docs and fix.', + error + ); + return false; + } + + this.sendCommerceEventToGA4( + mapGA4EcommerceEventName(event), + ga4CommerceEventParameters + ); + + return true; +}; + +CommerceHandler.prototype.logPromotionEvent = function (event) { + var ga4CommerceEventParameters; + try { + event.PromotionAction.PromotionList.forEach(function (promotion) { + ga4CommerceEventParameters = buildPromotion(promotion); + }); + } catch (error) { + console.error( + 'Error logging Promotions to GA4. Promotions not logged.', + error + ); + return false; + } + + this.sendCommerceEventToGA4( + mapGA4EcommerceEventName(event), + ga4CommerceEventParameters + ); + return true; +}; + +CommerceHandler.prototype.logImpressionEvent = function (event, affiliation) { + var ga4CommerceEventParameters; + try { + event.ProductImpressions.forEach(function (impression) { + ga4CommerceEventParameters = parseImpression( + impression, + affiliation + ); + }); + } catch (error) { + console.log( + 'Error logging Impressions to GA4. Impressions not logged', + error + ); + return false; + } + + this.sendCommerceEventToGA4( + mapGA4EcommerceEventName(event), + ga4CommerceEventParameters + ); + + return true; +}; + +CommerceHandler.prototype.logViewCart = function (event, affiliation) { + var ga4CommerceEventParameters = buildViewCart(event, affiliation); + ga4CommerceEventParameters = this.common.mergeObjects( + ga4CommerceEventParameters, + this.common.limitEventAttributes(event.EventAttributes) + ); + ga4CommerceEventParameters.currency = event.CurrencyCode; + + ga4CommerceEventParameters.value = + (event.CustomFlags && event.CustomFlags['GA4.Value']) || + event.ProductAction.TotalAmount || + null; + + this.sendCommerceEventToGA4( + mapGA4EcommerceEventName(event), + ga4CommerceEventParameters + ); +}; + function buildAddOrRemoveCartItem(event, affiliation) { return { items: buildProductsList(event.ProductAction.ProductList, affiliation), @@ -394,117 +528,6 @@ function getCheckoutOptionEventName(customFlags) { } } -// Google previously had a CheckoutOption event, and now this has been split into 2 GA4 events - add_shipping_info and add_payment_info -// Since MP still uses CheckoutOption, we must map this to the 2 events using custom flags. To prevent any data loss from customers -// migrating from UA to GA4, we will set a default `set_checkout_option` which matches Firebase's data model. -function logCheckoutOptionEvent(event, affiliation) { - try { - var customFlags = event.CustomFlags, - GA4CommerceEventType = customFlags[GA4_COMMERCE_EVENT_TYPE], - ga4CommerceEventParameters; - - // if no custom flags exist or there is no GA4CommerceEventType, the user has not updated their code from using legacy GA which still supports checkout_option - if (!customFlags || !GA4CommerceEventType) { - console.error( - 'Your checkout option event for the Google Analytics 4 integration is missing a custom flag for "GA4.CommerceEventType". The event was sent using the deprecated set_checkout_option event. Review mParticle docs for GA4 for the custom flags to add.' - ); - } - - switch (GA4CommerceEventType) { - case ADD_SHIPPING_INFO: - ga4CommerceEventParameters = buildAddShippingInfo( - event, - affiliation - ); - break; - case ADD_PAYMENT_INFO: - ga4CommerceEventParameters = buildAddPaymentInfo( - event, - affiliation - ); - break; - default: - ga4CommerceEventParameters = buildCheckoutOptions( - event, - affiliation - ); - break; - } - } catch (error) { - console.error( - 'There is an issue with the custom flags in your CheckoutOption event. The event was not sent. Plrease review the docs and fix.', - error - ); - return false; - } - - gtag('event', mapGA4EcommerceEventName(event), ga4CommerceEventParameters); - - return true; -} - -function logPromotionEvent(event) { - try { - var ga4CommerceEventParameters; - event.PromotionAction.PromotionList.forEach(function (promotion) { - ga4CommerceEventParameters = buildPromotion(promotion); - gtag( - 'event', - mapGA4EcommerceEventName(event), - ga4CommerceEventParameters - ); - }); - return true; - } catch (error) { - console.error( - 'Error logging Promotions to GA4. Promotions not logged.', - error - ); - } - return false; -} - -function logImpressionEvent(event, affiliation) { - try { - var ga4CommerceEventParameters; - event.ProductImpressions.forEach(function (impression) { - ga4CommerceEventParameters = parseImpression( - impression, - affiliation - ); - - gtag( - 'event', - mapGA4EcommerceEventName(event), - ga4CommerceEventParameters - ); - }); - } catch (error) { - console.log( - 'Error logging Impressions to GA4. Impressions not logged', - error - ); - return false; - } - return true; -} - -function logViewCart(event, affiliation) { - var ga4CommerceEventParameters = buildViewCart(event, affiliation); - ga4CommerceEventParameters = self.common.mergeObjects( - ga4CommerceEventParameters, - self.common.limitEventAttributes(event.EventAttributes) - ); - ga4CommerceEventParameters.currency = event.CurrencyCode; - - ga4CommerceEventParameters.value = - (event.CustomFlags && event.CustomFlags['GA4.Value']) || - event.ProductAction.TotalAmount || - null; - gtag('event', mapGA4EcommerceEventName(event), ga4CommerceEventParameters); - return true; -} - function buildViewCart(event, affiliation) { return { items: buildProductsList(event.ProductAction.ProductList, affiliation), diff --git a/packages/GA4Client/src/event-handler.js b/packages/GA4Client/src/event-handler.js index 9c875b5..2a47939 100644 --- a/packages/GA4Client/src/event-handler.js +++ b/packages/GA4Client/src/event-handler.js @@ -45,6 +45,11 @@ EventHandler.prototype.sendEventToGA4 = function (eventName, eventAttributes) { standardizedAttributes ); + if (this.common.forwarderSettings.measurementId) { + standardizedAttributes.send_to = + this.common.forwarderSettings.measurementId; + } + gtag( 'event', this.common.truncateEventName(standardizedEventName), From a9d62736521320ff26006cb8a299675f207d0381 Mon Sep 17 00:00:00 2001 From: Mo Mustafa Date: Mon, 4 Mar 2024 11:56:00 -0800 Subject: [PATCH 2/5] fix: include measurement Id as event param --- packages/GA4Client/src/commerce-handler.js | 33 ++++++++++++---------- packages/GA4Client/src/common.js | 3 +- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/packages/GA4Client/src/commerce-handler.js b/packages/GA4Client/src/commerce-handler.js index 15c407a..cf02373 100644 --- a/packages/GA4Client/src/commerce-handler.js +++ b/packages/GA4Client/src/commerce-handler.js @@ -210,10 +210,17 @@ CommerceHandler.prototype.logCheckoutOptionEvent = function ( }; CommerceHandler.prototype.logPromotionEvent = function (event) { - var ga4CommerceEventParameters; + var self = this; try { + var ga4CommerceEventParameters; event.PromotionAction.PromotionList.forEach(function (promotion) { ga4CommerceEventParameters = buildPromotion(promotion); + + self.sendCommerceEventToGA4( + mapGA4EcommerceEventName(event), + ga4CommerceEventParameters + ); + return true; }); } catch (error) { console.error( @@ -222,22 +229,25 @@ CommerceHandler.prototype.logPromotionEvent = function (event) { ); return false; } - - this.sendCommerceEventToGA4( - mapGA4EcommerceEventName(event), - ga4CommerceEventParameters - ); - return true; }; CommerceHandler.prototype.logImpressionEvent = function (event, affiliation) { - var ga4CommerceEventParameters; + var self = this; try { + var ga4CommerceEventParameters; event.ProductImpressions.forEach(function (impression) { ga4CommerceEventParameters = parseImpression( impression, affiliation ); + + + self.sendCommerceEventToGA4( + mapGA4EcommerceEventName(event), + ga4CommerceEventParameters + ); + + return true; }); } catch (error) { console.log( @@ -246,13 +256,6 @@ CommerceHandler.prototype.logImpressionEvent = function (event, affiliation) { ); return false; } - - this.sendCommerceEventToGA4( - mapGA4EcommerceEventName(event), - ga4CommerceEventParameters - ); - - return true; }; CommerceHandler.prototype.logViewCart = function (event, affiliation) { diff --git a/packages/GA4Client/src/common.js b/packages/GA4Client/src/common.js index 1c20642..6ac4fff 100644 --- a/packages/GA4Client/src/common.js +++ b/packages/GA4Client/src/common.js @@ -7,7 +7,8 @@ var ConsentHandler = require('./consent'); var EVENT_NAME_MAX_LENGTH = 40; var EVENT_ATTRIBUTE_KEY_MAX_LENGTH = 40; var EVENT_ATTRIBUTE_VAL_MAX_LENGTH = 100; -var EVENT_ATTRIBUTE_MAX_NUMBER = 100; +// maximum event attributes reduced to 99 instead of 100 since now we include send_to as GA4 event parameter +var EVENT_ATTRIBUTE_MAX_NUMBER = 99; var USER_ATTRIBUTE_KEY_MAX_LENGTH = 24; var USER_ATTRIBUTE_VALUE_MAX_LENGTH = 36; From 4a837f0c4f26668738d8775862d37c87b4fea6a4 Mon Sep 17 00:00:00 2001 From: Mo Mustafa Date: Mon, 4 Mar 2024 11:58:21 -0800 Subject: [PATCH 3/5] fix: include measurement Id as event param --- packages/GA4Client/test/src/tests.js | 50 +++++++++++++++++++++------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/packages/GA4Client/test/src/tests.js b/packages/GA4Client/test/src/tests.js index 0bcf74b..0fe67c3 100644 --- a/packages/GA4Client/test/src/tests.js +++ b/packages/GA4Client/test/src/tests.js @@ -325,6 +325,7 @@ describe('Google Analytics 4 Event', function () { total_amount: 999, }, ], + send_to: 'testMeasurementId', }, ]; @@ -825,6 +826,7 @@ describe('Google Analytics 4 Event', function () { total_amount: 999, }, ], + send_to: 'testMeasurementId', }, ]; @@ -924,6 +926,7 @@ describe('Google Analytics 4 Event', function () { promotion_name: 'Summer Sale Banner', creative_name: 'Summer Sale', creative_slot: 'featured_app_1', + send_to: 'testMeasurementId', }, ]; @@ -935,9 +938,10 @@ describe('Google Analytics 4 Event', function () { promotion_name: 'Winter Sale Banner', creative_name: 'Winter Sale', creative_slot: 'featured_app_2', + send_to: 'testMeasurementId', }, ]; - + window.dataLayer[0].should.eql(promotionResult1); window.dataLayer[1].should.eql(promotionResult2); @@ -977,6 +981,7 @@ describe('Google Analytics 4 Event', function () { promotion_name: 'Summer Sale Banner', creative_name: 'Summer Sale', creative_slot: 'featured_app_1', + send_to: 'testMeasurementId', }, ]; @@ -988,6 +993,7 @@ describe('Google Analytics 4 Event', function () { promotion_name: 'Winter Sale Banner', creative_name: 'Winter Sale', creative_slot: 'featured_app_2', + send_to: 'testMeasurementId', }, ]; @@ -1086,6 +1092,7 @@ describe('Google Analytics 4 Event', function () { total_amount: 999, }, ], + send_to: 'testMeasurementId', }, ]; @@ -1183,6 +1190,7 @@ describe('Google Analytics 4 Event', function () { total_amount: 999, }, ], + send_to: 'testMeasurementId', }, ]; @@ -1242,6 +1250,7 @@ describe('Google Analytics 4 Event', function () { shipping_tier: null, coupon: null, items: [], + send_to: 'testMeasurementId', }, ]; window.dataLayer[0].should.eql(result); @@ -1271,6 +1280,7 @@ describe('Google Analytics 4 Event', function () { payment_type: null, coupon: null, items: [], + send_to: 'testMeasurementId', }, ]; window.dataLayer[0].should.eql(result); @@ -1363,6 +1373,7 @@ describe('Google Analytics 4 Event', function () { total_amount: 999, }, ], + send_to: 'testMeasurementId', }, ]; @@ -1458,7 +1469,7 @@ describe('Google Analytics 4 Event', function () { EventAttributes: {}, }); - var result = ['event', 'Unmapped Event Name', {}]; + var result = ['event', 'Unmapped Event Name', { send_to: 'testMeasurementId', }]; window.dataLayer[0].should.eql(result); done(); @@ -1472,7 +1483,7 @@ describe('Google Analytics 4 Event', function () { EventAttributes: null, }); - var result = ['event', 'Unmapped Event Name', {}]; + var result = ['event', 'Unmapped Event Name', { send_to: 'testMeasurementId', }]; window.dataLayer[0].should.eql(result); done(); @@ -1488,7 +1499,7 @@ describe('Google Analytics 4 Event', function () { }, }); - var result = ['event', 'Unmapped Event Name', { foo: 'bar' }]; + var result = ['event', 'Unmapped Event Name', { foo: 'bar', send_to: 'testMeasurementId', }]; window.dataLayer[0].should.eql(result); done(); @@ -1512,6 +1523,7 @@ describe('Google Analytics 4 Event', function () { { page_title: 'Mocha Tests', page_location: location.href, + send_to: 'testMeasurementId', }, ]; window.dataLayer[0].should.eql(result); @@ -1541,6 +1553,7 @@ describe('Google Analytics 4 Event', function () { page_location: '/foo', eventKey1: 'test1', eventKey2: 'test2', + send_to: 'testMeasurementId', }, ]; window.dataLayer[0].should.eql(result); @@ -1568,6 +1581,7 @@ describe('Google Analytics 4 Event', function () { foo: 'bar', superLongEventAttributeNameThatShouldBeT: 'Super Long Event Attribute value that should be truncated because we do not want super long attribut', + send_to: 'testMeasurementId', }; window.dataLayer[0][1].should.eql(expectedEventName); @@ -1605,6 +1619,7 @@ describe('Google Analytics 4 Event', function () { var expectedEventAttributes = { foo: 'bar', '1?test4ever!!!': 'tester', + send_to: 'testMeasurementId', }; window.dataLayer[0][1].should.eql(expectedEventName); @@ -1630,6 +1645,7 @@ describe('Google Analytics 4 Event', function () { { page_title: 'Foo Page Title', page_location: '/foo', + send_to: 'testMeasurementId', }, ]; @@ -1654,6 +1670,7 @@ describe('Google Analytics 4 Event', function () { { page_title: 'Foo Page Title', page_location: '/foo', + send_to: 'testMeasurementId', }, ]; window.dataLayer[0].should.eql(result); @@ -1663,7 +1680,7 @@ describe('Google Analytics 4 Event', function () { describe('limit event attributes', function () { // 101 event attribute keys because the limit is 100 - var eventAttributeKeys101 = [ + var eventAttributeKeys100 = [ 'aa', 'ab', 'ac', @@ -1764,7 +1781,6 @@ describe('Google Analytics 4 Event', function () { 'dt', 'du', 'dv', - 'dw', ]; it('should limit the number of event attribute keys', function (done) { @@ -1776,7 +1792,7 @@ describe('Google Analytics 4 Event', function () { EventAttributes: {}, }; // add on 101 event attributes - eventAttributeKeys101.forEach(function (key) { + eventAttributeKeys100.forEach(function (key) { event.EventAttributes[key] = key; }); mParticle.forwarder.process(event); @@ -1784,7 +1800,9 @@ describe('Google Analytics 4 Event', function () { var resultEventAttributeKeys = Object.keys(dataLayer[0][2]); resultEventAttributeKeys.length.should.eql(100); // dw is the 101st item. The limit is 100, so - resultEventAttributeKeys.should.not.have.property('dw'); + resultEventAttributeKeys.should.not.have.property('dv'); + // confirm measurmentId as part of GA4 parameters + resultEventAttributeKeys.should.not.have.property('send_to'); done(); }); @@ -1807,15 +1825,17 @@ describe('Google Analytics 4 Event', function () { }; // add on 101 event attributes - eventAttributeKeys101.forEach(function (key) { + eventAttributeKeys100.forEach(function (key) { event.EventAttributes[key] = key; }); mParticle.forwarder.process(event); var resultEventAttributeKeys = Object.keys(dataLayer[0][2]); // confirm event attribuets have been successfully set resultEventAttributeKeys.includes('aa').should.equal(true); + // confirm measurmentId as part of GA4 parameters + resultEventAttributeKeys.includes('send_to').should.equal(true); // dw is the 101st item. The limit is 100, so - resultEventAttributeKeys.includes('dw').should.equal(false); + resultEventAttributeKeys.includes('dv').should.equal(false); done(); }); @@ -1834,7 +1854,7 @@ describe('Google Analytics 4 Event', function () { }; // add on 101 event attributes - eventAttributeKeys101.forEach(function (key) { + eventAttributeKeys100.forEach(function (key) { event.EventAttributes[key] = key; }); @@ -1843,8 +1863,10 @@ describe('Google Analytics 4 Event', function () { var resultEventAttributeKeys = Object.keys(dataLayer[0][2]); // confirm event attribuets have been successfully set resultEventAttributeKeys.includes('aa').should.equal(true); + // confirm measurmentId as part of GA4 parameters + resultEventAttributeKeys.includes('send_to').should.equal(true); // dw is the 101st item. The limit is 100, so - resultEventAttributeKeys.includes('dw').should.equal(false); + resultEventAttributeKeys.includes('dv').should.equal(false); done(); }); @@ -2032,6 +2054,7 @@ describe('Google Analytics 4 Event', function () { var expectedEventAttributes = { foo: 'bar', test4ever___: 'tester', + send_to: 'testMeasurementId', }; window.dataLayer[0][1].should.eql(expectedEventName); @@ -2060,6 +2083,7 @@ describe('Google Analytics 4 Event', function () { var expectedEventAttributes = { fo: 'bar', test4ever__: 'tester', + send_to: 'testMeasurementId', }; window.dataLayer[0][1].should.eql(expectedEventName); @@ -2193,6 +2217,7 @@ describe('Google Analytics 4 Event', function () { }, ], currency: 'USD', + send_to: 'testMeasurementId', }, ]; @@ -2294,6 +2319,7 @@ describe('Google Analytics 4 Event', function () { total_amount: 999, }, ], + send_to: 'testMeasurementId' }, ]; From 8cb4c21540514f9a500c13b48fbdba789ffdb220 Mon Sep 17 00:00:00 2001 From: Mo Mustafa Date: Wed, 6 Mar 2024 15:25:33 -0800 Subject: [PATCH 4/5] fix: include measurement Id as event param --- packages/GA4Client/src/commerce-handler.js | 19 +++++----- packages/GA4Client/src/common.js | 3 +- packages/GA4Client/test/src/tests.js | 42 +++++++++++++++------- 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/packages/GA4Client/src/commerce-handler.js b/packages/GA4Client/src/commerce-handler.js index cf02373..4c0f825 100644 --- a/packages/GA4Client/src/commerce-handler.js +++ b/packages/GA4Client/src/commerce-handler.js @@ -136,11 +136,10 @@ CommerceHandler.prototype.logCommerceEvent = function (event) { null; } - this.sendCommerceEventToGA4( + return this.sendCommerceEventToGA4( mapGA4EcommerceEventName(event), ga4CommerceEventParameters ); - return true; }; CommerceHandler.prototype.sendCommerceEventToGA4 = function ( @@ -152,6 +151,8 @@ CommerceHandler.prototype.sendCommerceEventToGA4 = function ( } gtag('event', eventName, eventAttributes); + + return true; }; // Google previously had a CheckoutOption event, and now this has been split into 2 GA4 events - add_shipping_info and add_payment_info @@ -201,12 +202,10 @@ CommerceHandler.prototype.logCheckoutOptionEvent = function ( return false; } - this.sendCommerceEventToGA4( + return this.sendCommerceEventToGA4( mapGA4EcommerceEventName(event), ga4CommerceEventParameters ); - - return true; }; CommerceHandler.prototype.logPromotionEvent = function (event) { @@ -220,8 +219,9 @@ CommerceHandler.prototype.logPromotionEvent = function (event) { mapGA4EcommerceEventName(event), ga4CommerceEventParameters ); - return true; }); + + return true; } catch (error) { console.error( 'Error logging Promotions to GA4. Promotions not logged.', @@ -241,14 +241,13 @@ CommerceHandler.prototype.logImpressionEvent = function (event, affiliation) { affiliation ); - self.sendCommerceEventToGA4( mapGA4EcommerceEventName(event), ga4CommerceEventParameters ); - - return true; }); + + return true; } catch (error) { console.log( 'Error logging Impressions to GA4. Impressions not logged', @@ -271,7 +270,7 @@ CommerceHandler.prototype.logViewCart = function (event, affiliation) { event.ProductAction.TotalAmount || null; - this.sendCommerceEventToGA4( + return this.sendCommerceEventToGA4( mapGA4EcommerceEventName(event), ga4CommerceEventParameters ); diff --git a/packages/GA4Client/src/common.js b/packages/GA4Client/src/common.js index 6ac4fff..1c20642 100644 --- a/packages/GA4Client/src/common.js +++ b/packages/GA4Client/src/common.js @@ -7,8 +7,7 @@ var ConsentHandler = require('./consent'); var EVENT_NAME_MAX_LENGTH = 40; var EVENT_ATTRIBUTE_KEY_MAX_LENGTH = 40; var EVENT_ATTRIBUTE_VAL_MAX_LENGTH = 100; -// maximum event attributes reduced to 99 instead of 100 since now we include send_to as GA4 event parameter -var EVENT_ATTRIBUTE_MAX_NUMBER = 99; +var EVENT_ATTRIBUTE_MAX_NUMBER = 100; var USER_ATTRIBUTE_KEY_MAX_LENGTH = 24; var USER_ATTRIBUTE_VALUE_MAX_LENGTH = 36; diff --git a/packages/GA4Client/test/src/tests.js b/packages/GA4Client/test/src/tests.js index 0fe67c3..4bff02b 100644 --- a/packages/GA4Client/test/src/tests.js +++ b/packages/GA4Client/test/src/tests.js @@ -1680,7 +1680,7 @@ describe('Google Analytics 4 Event', function () { describe('limit event attributes', function () { // 101 event attribute keys because the limit is 100 - var eventAttributeKeys100 = [ + var eventAttributeKeys101 = [ 'aa', 'ab', 'ac', @@ -1781,6 +1781,7 @@ describe('Google Analytics 4 Event', function () { 'dt', 'du', 'dv', + 'dw' ]; it('should limit the number of event attribute keys', function (done) { @@ -1792,17 +1793,22 @@ describe('Google Analytics 4 Event', function () { EventAttributes: {}, }; // add on 101 event attributes - eventAttributeKeys100.forEach(function (key) { + eventAttributeKeys101.forEach(function (key) { event.EventAttributes[key] = key; }); mParticle.forwarder.process(event); var resultEventAttributeKeys = Object.keys(dataLayer[0][2]); + // confirm measurmentId as part of GA4 parameters + resultEventAttributeKeys.includes('send_to').should.equal(true); + // remove send_to to test the 100 event attribute limit since send_to is a reserved GA4 param + delete (dataLayer[0][2]).send_to + + // re-assign resultEventAttributeKeys after removing send_to from batch to only count for non-reserved params + resultEventAttributeKeys = Object.keys(dataLayer[0][2]); resultEventAttributeKeys.length.should.eql(100); // dw is the 101st item. The limit is 100, so - resultEventAttributeKeys.should.not.have.property('dv'); - // confirm measurmentId as part of GA4 parameters - resultEventAttributeKeys.should.not.have.property('send_to'); + resultEventAttributeKeys.should.not.have.property('dw'); done(); }); @@ -1825,17 +1831,22 @@ describe('Google Analytics 4 Event', function () { }; // add on 101 event attributes - eventAttributeKeys100.forEach(function (key) { + eventAttributeKeys101.forEach(function (key) { event.EventAttributes[key] = key; }); mParticle.forwarder.process(event); var resultEventAttributeKeys = Object.keys(dataLayer[0][2]); - // confirm event attribuets have been successfully set - resultEventAttributeKeys.includes('aa').should.equal(true); // confirm measurmentId as part of GA4 parameters resultEventAttributeKeys.includes('send_to').should.equal(true); + // remove send_to to test the 100 event attribute limit since send_to is a reserved GA4 param + delete (dataLayer[0][2]).send_to + + // re-assign resultEventAttributeKeys after removing send_to from batch to only count for non-reserved params + resultEventAttributeKeys = Object.keys(dataLayer[0][2]); + // confirm event attribuets have been successfully set + resultEventAttributeKeys.includes('aa').should.equal(true); // dw is the 101st item. The limit is 100, so - resultEventAttributeKeys.includes('dv').should.equal(false); + resultEventAttributeKeys.includes('dw').should.equal(false); done(); }); @@ -1854,19 +1865,24 @@ describe('Google Analytics 4 Event', function () { }; // add on 101 event attributes - eventAttributeKeys100.forEach(function (key) { + eventAttributeKeys101.forEach(function (key) { event.EventAttributes[key] = key; }); mParticle.forwarder.process(event); var resultEventAttributeKeys = Object.keys(dataLayer[0][2]); - // confirm event attribuets have been successfully set - resultEventAttributeKeys.includes('aa').should.equal(true); // confirm measurmentId as part of GA4 parameters resultEventAttributeKeys.includes('send_to').should.equal(true); + // remove send_to to test the 100 event attribute limit since send_to is a reserved GA4 param + delete (dataLayer[0][2]).send_to + + // re-assign resultEventAttributeKeys after removing send_to from batch to only count for non-reserved params + resultEventAttributeKeys = Object.keys(dataLayer[0][2]); + // confirm event attribuets have been successfully set + resultEventAttributeKeys.includes('aa').should.equal(true); // dw is the 101st item. The limit is 100, so - resultEventAttributeKeys.includes('dv').should.equal(false); + resultEventAttributeKeys.includes('dw').should.equal(false); done(); }); From c44dc26d0c353a0f7dfe4c833ecb8e6019b864ef Mon Sep 17 00:00:00 2001 From: Robert Ing Date: Thu, 7 Mar 2024 09:53:16 -0500 Subject: [PATCH 5/5] Update packages/GA4Client/test/src/tests.js Co-authored-by: Alex S <49695018+alexs-mparticle@users.noreply.github.com> --- packages/GA4Client/test/src/tests.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/GA4Client/test/src/tests.js b/packages/GA4Client/test/src/tests.js index 4bff02b..c6f8b6d 100644 --- a/packages/GA4Client/test/src/tests.js +++ b/packages/GA4Client/test/src/tests.js @@ -941,7 +941,6 @@ describe('Google Analytics 4 Event', function () { send_to: 'testMeasurementId', }, ]; - window.dataLayer[0].should.eql(promotionResult1); window.dataLayer[1].should.eql(promotionResult2);