From 95d36fe3fd25bec296bc45f6141551c835ea045d Mon Sep 17 00:00:00 2001 From: Ankit Gupta <139338151+AnkitSegment@users.noreply.github.com> Date: Tue, 21 May 2024 20:57:48 +0530 Subject: [PATCH] [MAIN] [STRATCONN] added consent for google campaign manager (#2021) * added consent for google campaign manager * added validation in GCM * change consent default to advertiserId * Added unit test cases * reset config changes * Increased size-limit * Added unit test case --- .../src/__tests__/index.test.ts | 185 ++++++++++++++++++ .../src/generated-types.ts | 20 ++ .../google-campaign-manager/src/index.ts | 77 +++++++- packages/browser-destinations/package.json | 2 +- 4 files changed, 282 insertions(+), 2 deletions(-) create mode 100644 packages/browser-destinations/destinations/google-campaign-manager/src/__tests__/index.test.ts diff --git a/packages/browser-destinations/destinations/google-campaign-manager/src/__tests__/index.test.ts b/packages/browser-destinations/destinations/google-campaign-manager/src/__tests__/index.test.ts new file mode 100644 index 0000000000..f8d817df1e --- /dev/null +++ b/packages/browser-destinations/destinations/google-campaign-manager/src/__tests__/index.test.ts @@ -0,0 +1,185 @@ +import { Subscription } from '@segment/browser-destination-runtime/types' +import googleCampaignManager, { destination } from '../index' +import { Analytics, Context } from '@segment/analytics-next' + +const subscriptions: Subscription[] = [ + { + partnerAction: 'salesActivity', + name: 'Sales Activity', + enabled: true, + subscribe: 'type = "track"', + mapping: {} + } +] + +describe('Google Tag for Campaign Manager', () => { + const defaultSettings = { + advertiserId: 'test123', + allowAdPersonalizationSignals: false, + conversionLinker: false + } + beforeEach(async () => { + jest.restoreAllMocks() + + const [googleCampaignManagerPlugin] = await googleCampaignManager({ + ...defaultSettings, + subscriptions + }) + jest.spyOn(destination, 'initialize') + + await googleCampaignManagerPlugin.load(Context.system(), {} as Analytics) + }) + + it('should not update consent if enable_consent mode is denied', async () => { + const settings = { + ...defaultSettings, + enableConsentMode: false + } + + const [event] = await googleCampaignManager({ ...settings, subscriptions }) + await event.load(Context.system(), {} as Analytics) + expect(destination.initialize).toHaveBeenCalled() + + expect(window.dataLayer).toEqual( + expect.arrayContaining([expect.not.objectContaining(Object.assign({}, ['consent', 'default', {}]))]) + ) + }) + + it('should update consent if analytics storage is granted', async () => { + const settings = { + ...defaultSettings, + enableConsentMode: true, + defaultAnalyticsStorageConsentState: 'granted' + } + + const [event] = await googleCampaignManager({ ...settings, subscriptions }) + await event.load(Context.system(), {} as Analytics) + expect(destination.initialize).toHaveBeenCalled() + + expect(window.dataLayer).toEqual( + expect.arrayContaining([ + expect.objectContaining(Object.assign({}, ['consent', 'default', { analytics_storage: 'granted' }])) + ]) + ) + }) + + it('should update consent if analytics storage is denied', async () => { + const settings = { + ...defaultSettings, + enableConsentMode: true, + defaultAnalyticsStorageConsentState: 'denied' + } + + const [event] = await googleCampaignManager({ ...settings, subscriptions }) + await event.load(Context.system(), {} as Analytics) + expect(destination.initialize).toHaveBeenCalled() + + expect(window.dataLayer).toEqual( + expect.arrayContaining([ + expect.objectContaining(Object.assign({}, ['consent', 'default', { analytics_storage: 'denied' }])) + ]) + ) + }) + it('should update consent if Ad storage is granted', async () => { + const settings = { + ...defaultSettings, + enableConsentMode: true, + defaultAdsStorageConsentState: 'granted' + } + + const [event] = await googleCampaignManager({ ...settings, subscriptions }) + await event.load(Context.system(), {} as Analytics) + expect(destination.initialize).toHaveBeenCalled() + + expect(window.dataLayer).toEqual( + expect.arrayContaining([ + expect.objectContaining(Object.assign({}, ['consent', 'default', { ad_storage: 'granted' }])) + ]) + ) + }) + it('should update consent if Ad storage is denied', async () => { + const settings = { + ...defaultSettings, + enableConsentMode: true, + defaultAdsStorageConsentState: 'denied' + } + + const [event] = await googleCampaignManager({ ...settings, subscriptions }) + await event.load(Context.system(), {} as Analytics) + expect(destination.initialize).toHaveBeenCalled() + + expect(window.dataLayer).toEqual( + expect.arrayContaining([ + expect.objectContaining(Object.assign({}, ['consent', 'default', { ad_storage: 'denied' }])) + ]) + ) + }) + it('should update consent if Ad user data is granted', async () => { + const settings = { + ...defaultSettings, + enableConsentMode: true, + adUserDataConsentState: 'granted' + } + + const [event] = await googleCampaignManager({ ...settings, subscriptions }) + await event.load(Context.system(), {} as Analytics) + expect(destination.initialize).toHaveBeenCalled() + + expect(window.dataLayer).toEqual( + expect.arrayContaining([ + expect.objectContaining(Object.assign({}, ['consent', 'default', { ad_user_data: 'granted' }])) + ]) + ) + }) + it('should update consent if Ad user data is denied', async () => { + const settings = { + ...defaultSettings, + enableConsentMode: true, + adUserDataConsentState: 'denied' + } + + const [event] = await googleCampaignManager({ ...settings, subscriptions }) + await event.load(Context.system(), {} as Analytics) + expect(destination.initialize).toHaveBeenCalled() + + expect(window.dataLayer).toEqual( + expect.arrayContaining([ + expect.objectContaining(Object.assign({}, ['consent', 'default', { ad_user_data: 'denied' }])) + ]) + ) + }) + it('should update consent if Ad personalization is granted', async () => { + const settings = { + ...defaultSettings, + enableConsentMode: true, + adPersonalizationConsentState: 'granted' + } + + const [event] = await googleCampaignManager({ ...settings, subscriptions }) + await event.load(Context.system(), {} as Analytics) + expect(destination.initialize).toHaveBeenCalled() + + expect(window.dataLayer).toEqual( + expect.arrayContaining([ + expect.objectContaining(Object.assign({}, ['consent', 'default', { ad_personalization: 'granted' }])) + ]) + ) + }) + it('should update consent if Ad personalization is denied', async () => { + const settings = { + ...defaultSettings, + enableConsentMode: true, + adPersonalizationConsentState: 'denied' + } + + const [event] = await googleCampaignManager({ ...settings, subscriptions }) + await event.load(Context.system(), {} as Analytics) + expect(destination.initialize).toHaveBeenCalled() + + expect(window.dataLayer).toEqual( + expect.arrayContaining([ + expect.objectContaining(Object.assign({}, ['consent', 'default', { ad_personalization: 'denied' }])) + ]) + ) + }) +}) diff --git a/packages/browser-destinations/destinations/google-campaign-manager/src/generated-types.ts b/packages/browser-destinations/destinations/google-campaign-manager/src/generated-types.ts index e7460761ba..70ed9aac4a 100644 --- a/packages/browser-destinations/destinations/google-campaign-manager/src/generated-types.ts +++ b/packages/browser-destinations/destinations/google-campaign-manager/src/generated-types.ts @@ -13,4 +13,24 @@ export interface Settings { * This feature can be disabled if you do not want the global site tag to set first party cookies on your site domain. */ conversionLinker: boolean + /** + * Set to true to enable Google’s [Consent Mode](https://support.google.com/analytics/answer/9976101?hl=en). Set to false by default. + */ + enableConsentMode?: boolean + /** + * Consent state indicated by the user for ad cookies. Value must be "granted" or "denied." This is only used if the Enable Consent Mode setting is on. + */ + adUserDataConsentState?: string + /** + * Consent state indicated by the user for ad cookies. Value must be "granted" or "denied." This is only used if the Enable Consent Mode setting is on. + */ + adPersonalizationConsentState?: string + /** + * The default value for ad cookies consent state. This is only used if Enable Consent Mode is on. Set to “granted” if it is not explicitly set. Consent state can be updated for each user in the Set Configuration Fields action. + */ + defaultAdsStorageConsentState?: string + /** + * The default value for analytics cookies consent state. This is only used if Enable Consent Mode is on. Set to “granted” if it is not explicitly set. Consent state can be updated for each user in the Set Configuration Fields action. + */ + defaultAnalyticsStorageConsentState?: string } diff --git a/packages/browser-destinations/destinations/google-campaign-manager/src/index.ts b/packages/browser-destinations/destinations/google-campaign-manager/src/index.ts index 482be16ddb..049804bd9a 100644 --- a/packages/browser-destinations/destinations/google-campaign-manager/src/index.ts +++ b/packages/browser-destinations/destinations/google-campaign-manager/src/index.ts @@ -11,6 +11,8 @@ declare global { } } +type ConsentParamsArg = 'granted' | 'denied' | undefined + export const destination: BrowserDestinationDefinition = { name: 'Google Tag for Campaign Manager', slug: 'actions-google-campaign-manager', @@ -40,6 +42,56 @@ export const destination: BrowserDestinationDefinition = { type: 'boolean', required: true, default: true + }, + enableConsentMode: { + description: `Set to true to enable Google’s [Consent Mode](https://support.google.com/analytics/answer/9976101?hl=en). Set to false by default.`, + label: 'Enable Consent Mode', + type: 'boolean', + default: false + }, + adUserDataConsentState: { + description: + 'Consent state indicated by the user for ad cookies. Value must be "granted" or "denied." This is only used if the Enable Consent Mode setting is on.', + label: 'Ad User Data Consent State', + type: 'string', + choices: [ + { label: 'Granted', value: 'granted' }, + { label: 'Denied', value: 'denied' } + ], + default: undefined + }, + adPersonalizationConsentState: { + description: + 'Consent state indicated by the user for ad cookies. Value must be "granted" or "denied." This is only used if the Enable Consent Mode setting is on.', + label: 'Ad Personalization Consent State', + type: 'string', + choices: [ + { label: 'Granted', value: 'granted' }, + { label: 'Denied', value: 'denied' } + ], + default: undefined + }, + defaultAdsStorageConsentState: { + description: + 'The default value for ad cookies consent state. This is only used if Enable Consent Mode is on. Set to “granted” if it is not explicitly set. Consent state can be updated for each user in the Set Configuration Fields action.', + label: 'Default Ads Storage Consent State', + type: 'string', + choices: [ + { label: 'Granted', value: 'granted' }, + { label: 'Denied', value: 'denied' } + ], + default: undefined + }, + defaultAnalyticsStorageConsentState: { + description: + 'The default value for analytics cookies consent state. This is only used if Enable Consent Mode is on. Set to “granted” if it is not explicitly set. Consent state can be updated for each user in the Set Configuration Fields action.', + label: 'Default Analytics Storage Consent State', + type: 'string', + choices: [ + { label: 'Granted', value: 'granted' }, + { label: 'Denied', value: 'denied' } + ], + default: undefined } }, @@ -49,12 +101,35 @@ export const destination: BrowserDestinationDefinition = { // eslint-disable-next-line prefer-rest-params window.dataLayer.push(arguments) } - window.gtag('set', 'allow_ad_personalization_signals', settings.allowAdPersonalizationSignals) window.gtag('js', new Date()) window.gtag('config', settings.advertiserId, { conversion_linker: settings.conversionLinker }) + if (settings.enableConsentMode) { + const consent: { + ad_storage?: ConsentParamsArg + analytics_storage?: ConsentParamsArg + ad_user_data?: ConsentParamsArg + ad_personalization?: ConsentParamsArg + allow_ad_personalization_signals?: Boolean + } = {} + + if (settings.defaultAnalyticsStorageConsentState) { + consent.analytics_storage = settings.defaultAnalyticsStorageConsentState as ConsentParamsArg + } + if (settings.defaultAdsStorageConsentState) { + consent.ad_storage = settings.defaultAdsStorageConsentState as ConsentParamsArg + } + if (settings.adUserDataConsentState) { + consent.ad_user_data = settings.adUserDataConsentState as ConsentParamsArg + } + if (settings.adPersonalizationConsentState) { + consent.ad_personalization = settings.adPersonalizationConsentState as ConsentParamsArg + } + + window.gtag('consent', 'default', consent) + } const script = `https://www.googletagmanager.com/gtag/js?id=${settings.advertiserId}` await deps.loadScript(script) return window.gtag diff --git a/packages/browser-destinations/package.json b/packages/browser-destinations/package.json index 7be820c1b1..b26391113a 100644 --- a/packages/browser-destinations/package.json +++ b/packages/browser-destinations/package.json @@ -84,7 +84,7 @@ "size-limit": [ { "path": "dist/web/*/*.js", - "limit": "151 KB" + "limit": "152 KB" } ] }