From 3d06c914d7a8503d3307f3311ab8062328f64b12 Mon Sep 17 00:00:00 2001 From: dmytro-po Date: Fri, 6 Jun 2025 13:25:37 +0300 Subject: [PATCH 1/4] AGT-553: ppid to GAM --- modules/intentIqIdSystem.js | 16 +++++ test/spec/modules/intentIqIdSystem_spec.js | 76 +++++++++++++++++++++- 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/modules/intentIqIdSystem.js b/modules/intentIqIdSystem.js index 78f193eda11..f72c089be8d 100644 --- a/modules/intentIqIdSystem.js +++ b/modules/intentIqIdSystem.js @@ -303,6 +303,20 @@ function storeCounters(storage, partnerData) { storeData(PARTNER_DATA_KEY, JSON.stringify(partnerData), storage, firstPartyData); } +export function setPPID(gamObjectReference, shouldSetPPID, eids) { + if (!shouldSetPPID || !isPlainObject(gamObjectReference) || !Array.isArray(eids)) return; + + const intentIqEid = eids.find(eid => eid.source === 'intentiq.com'); + if (!intentIqEid?.uids?.length) return; + + const ppuid = intentIqEid.uids.find(uid => uid.ext?.stype === 'ppuid')?.id; + if (!ppuid) return; + + gamObjectReference.cmd?.push(() => { + gamObjectReference.pubads().setPublisherProvidedId(ppuid); + }); +} + /** @type {Submodule} */ export const intentIqIdSubmodule = { /** @@ -470,6 +484,7 @@ export const intentIqIdSubmodule = { if (firstPartyData.group === WITHOUT_IIQ || (firstPartyData.group !== WITHOUT_IIQ && runtimeEids?.eids?.length)) { firePartnerCallback() + setPPID(gamObjectReference, configParams.shouldSetPPID, runtimeEids.eids); } // Check if current browser is in blacklist @@ -611,6 +626,7 @@ export const intentIqIdSubmodule = { if (respJson.data?.eids) { runtimeEids = respJson.data + setPPID(gamObjectReference, configParams.shouldSetPPID, runtimeEids.eids); callback(respJson.data.eids); firePartnerCallback() const encryptedData = encryptData(JSON.stringify(respJson.data)) diff --git a/test/spec/modules/intentIqIdSystem_spec.js b/test/spec/modules/intentIqIdSystem_spec.js index 49da8fa3267..4c7192d3e1a 100644 --- a/test/spec/modules/intentIqIdSystem_spec.js +++ b/test/spec/modules/intentIqIdSystem_spec.js @@ -302,21 +302,91 @@ describe('IntentIQ tests', function () { }); it('should use the provided gamParameterName from configParams', function () { - let callBackSpy = sinon.spy(); let mockGamObject = mockGAM(); let customParamName = 'custom_gam_param'; defaultConfigParams.params.gamObjectReference = mockGamObject; defaultConfigParams.params.gamParameterName = customParamName; - let submoduleCallback = intentIqIdSubmodule.getId(defaultConfigParams).callback; - submoduleCallback(callBackSpy); + intentIqIdSubmodule.getId(defaultConfigParams) mockGamObject.cmd.forEach(cb => cb()); let targetingKeys = mockGamObject.pubads().getTargetingKeys(); expect(targetingKeys).to.include(customParamName); }); + it('should call setPublisherProvidedId if shouldSetPPID=true', function () { + const ppidSpy = sinon.spy(); + const gam = { + cmd: [], + pubads: function () { + return { + setTargeting: sinon.spy(), + setPublisherProvidedId: ppidSpy + }; + } + }; + defaultConfigParams.params.gamObjectReference = gam; + defaultConfigParams.params.shouldSetPPID = true; + + intentIqIdSubmodule.getId(defaultConfigParams).callback(() => {}); + + const request = server.requests[0]; + request.respond(200, responseHeader, JSON.stringify({ + data: { + eids: [ + { + source: 'intentiq.com', + uids: [ + { + id: 'test_id', + ext: { stype: 'ppuid' } + } + ] + } + ] + } + }) + ); + + gam.cmd.forEach(cb => cb()); + + expect(request.url).to.contain('at=39'); + expect(ppidSpy.calledOnce).to.be.true; + expect(ppidSpy.firstCall.args[0]).to.equal('test_id'); + }); + + it('should NOT call setPublisherProvidedId if shouldSetPPID=false', function () { + const ppidSpy = sinon.spy(); + const gam = { + cmd: [], + pubads: () => ({ + setTargeting: sinon.spy(), + setPublisherProvidedId: ppidSpy + }) + }; + defaultConfigParams.params.gamObjectReference = gam; + defaultConfigParams.params.shouldSetPPID = false; + intentIqIdSubmodule.getId(defaultConfigParams).callback(() => {}); + + const request = server.requests[0]; + request.respond(200, responseHeader, JSON.stringify({ + data: { + eids: [{ + source: 'intentiq.com', + uids: [{ + id: 'test_id', + ext: { stype: 'ppuid' } + }] + }] + } + })); + + gam.cmd.forEach(cb => cb()); + expect(request.url).to.contain('at=39'); + expect(ppidSpy.called).to.be.false; + }); + it('should not throw Uncaught TypeError when IntentIQ endpoint returns empty response', function () { let callBackSpy = sinon.spy(); let submoduleCallback = intentIqIdSubmodule.getId(defaultConfigParams).callback; From d5338c4fb1f603be54df04919da565d4d8314b7e Mon Sep 17 00:00:00 2001 From: dmytro-po Date: Tue, 10 Jun 2025 17:17:15 +0300 Subject: [PATCH 2/4] AGT-553: Fix after review and add test for LS --- modules/intentIqIdSystem.js | 2 +- test/spec/modules/intentIqIdSystem_spec.js | 26 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/modules/intentIqIdSystem.js b/modules/intentIqIdSystem.js index f72c089be8d..90fe0573614 100644 --- a/modules/intentIqIdSystem.js +++ b/modules/intentIqIdSystem.js @@ -458,6 +458,7 @@ export const intentIqIdSubmodule = { if (partnerData.data.length) { // encrypted data decryptedData = tryParse(decryptData(partnerData.data)); runtimeEids = decryptedData; + setPPID(gamObjectReference, configParams.shouldSetPPID, runtimeEids.eids); } } @@ -484,7 +485,6 @@ export const intentIqIdSubmodule = { if (firstPartyData.group === WITHOUT_IIQ || (firstPartyData.group !== WITHOUT_IIQ && runtimeEids?.eids?.length)) { firePartnerCallback() - setPPID(gamObjectReference, configParams.shouldSetPPID, runtimeEids.eids); } // Check if current browser is in blacklist diff --git a/test/spec/modules/intentIqIdSystem_spec.js b/test/spec/modules/intentIqIdSystem_spec.js index 4c7192d3e1a..195f1218145 100644 --- a/test/spec/modules/intentIqIdSystem_spec.js +++ b/test/spec/modules/intentIqIdSystem_spec.js @@ -356,6 +356,31 @@ describe('IntentIQ tests', function () { expect(ppidSpy.firstCall.args[0]).to.equal('test_id'); }); + it('should call setPublisherProvidedId if shouldSetPPID=true and ids are present in LS', function () { + const ppidSpy = sinon.spy(); + const gam = { + cmd: [], + pubads: function () { + return { + setTargeting: sinon.spy(), + setPublisherProvidedId: ppidSpy + }; + } + }; + + defaultConfigParams.params.gamObjectReference = gam; + defaultConfigParams.params.shouldSetPPID = true; + + localStorage.setItem('_iiq_fdata_' + partner, JSON.stringify(testLSValueWithData)); + + intentIqIdSubmodule.getId(defaultConfigParams); + gam.cmd.forEach(fn => typeof fn === 'function' && fn()); + + const expectedEid = JSON.parse(decryptData(testLSValueWithData.data)).eids[0].uids[0].id; + expect(ppidSpy.calledOnce).to.be.true; + expect(ppidSpy.firstCall.args[0]).to.equal(expectedEid); + }); + it('should NOT call setPublisherProvidedId if shouldSetPPID=false', function () { const ppidSpy = sinon.spy(); const gam = { @@ -465,6 +490,7 @@ describe('IntentIQ tests', function () { it('return data stored in local storage ', function () { localStorage.setItem('_iiq_fdata_' + partner, JSON.stringify(testLSValueWithData)); + let returnedValue = intentIqIdSubmodule.getId(allConfigParams); expect(returnedValue.id).to.deep.equal(JSON.parse(decryptData(testLSValueWithData.data)).eids); }); From 728f0717ff6341a5ea924c0a7d9e2269cdb97900 Mon Sep 17 00:00:00 2001 From: dmytro-po Date: Wed, 11 Jun 2025 09:50:15 +0300 Subject: [PATCH 3/4] AGT-553: Tests refactoring --- test/spec/modules/intentIqIdSystem_spec.js | 26 +++++----------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/test/spec/modules/intentIqIdSystem_spec.js b/test/spec/modules/intentIqIdSystem_spec.js index 195f1218145..01c36b69de1 100644 --- a/test/spec/modules/intentIqIdSystem_spec.js +++ b/test/spec/modules/intentIqIdSystem_spec.js @@ -58,7 +58,7 @@ export const testClientHints = { const testAPILink = 'https://new-test-api.intentiq.com' const syncTestAPILink = 'https://new-test-sync.intentiq.com' -const mockGAM = () => { +const mockGAM = (ppidSpy = sinon.spy()) => { const targetingObject = {}; return { cmd: [], @@ -71,7 +71,8 @@ const mockGAM = () => { }, getTargetingKeys: () => { return Object.keys(targetingObject); - } + }, + setPublisherProvidedId: ppidSpy }) }; }; @@ -317,15 +318,8 @@ describe('IntentIQ tests', function () { it('should call setPublisherProvidedId if shouldSetPPID=true', function () { const ppidSpy = sinon.spy(); - const gam = { - cmd: [], - pubads: function () { - return { - setTargeting: sinon.spy(), - setPublisherProvidedId: ppidSpy - }; - } - }; + const gam = mockGAM(ppidSpy); + defaultConfigParams.params.gamObjectReference = gam; defaultConfigParams.params.shouldSetPPID = true; @@ -358,15 +352,7 @@ describe('IntentIQ tests', function () { it('should call setPublisherProvidedId if shouldSetPPID=true and ids are present in LS', function () { const ppidSpy = sinon.spy(); - const gam = { - cmd: [], - pubads: function () { - return { - setTargeting: sinon.spy(), - setPublisherProvidedId: ppidSpy - }; - } - }; + const gam = mockGAM(ppidSpy); defaultConfigParams.params.gamObjectReference = gam; defaultConfigParams.params.shouldSetPPID = true; From 59ce1c6d91f3e660acaed9684d26aca0be4be63e Mon Sep 17 00:00:00 2001 From: dmytro-po Date: Wed, 11 Jun 2025 10:43:41 +0300 Subject: [PATCH 4/4] AGT-553: shouldSetPPID parameter documentation --- libraries/intentIqConstants/intentIqConstants.js | 2 +- modules/intentIqIdSystem.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/intentIqConstants/intentIqConstants.js b/libraries/intentIqConstants/intentIqConstants.js index 05a0bfb0885..820c8364372 100644 --- a/libraries/intentIqConstants/intentIqConstants.js +++ b/libraries/intentIqConstants/intentIqConstants.js @@ -9,7 +9,7 @@ export const BLACK_LIST = 'L'; export const CLIENT_HINTS_KEY = '_iiq_ch'; export const EMPTY = 'EMPTY'; export const GVLID = '1323'; -export const VERSION = 0.29; +export const VERSION = 0.30; export const PREBID = 'pbjs'; export const HOURS_24 = 86400000; diff --git a/modules/intentIqIdSystem.md b/modules/intentIqIdSystem.md index 644fe07fcd2..dec7fe8d6cd 100644 --- a/modules/intentIqIdSystem.md +++ b/modules/intentIqIdSystem.md @@ -59,6 +59,7 @@ Please find below list of parameters that could be used in configuring Intent IQ | params.additionalParameters [0].parameterName | Required | String | Name of the custom parameter. This will be sent as a query parameter. | `"abc"` | | params.additionalParameters [0].parameterValue | Required | String / Number | Value to assign to the parameter. | `123` | | params.additionalParameters [0].destination | Required | Array | Array of numbers either `1` or `0`. Controls where this parameter is sent `[sendWithSync, sendWithVr, winreport]`. | `[1, 0, 0]` | +| params.shouldSetPPID | Optional | Boolean | Enables the Intent IQ ID to be sent to Google Ad Manager as a Publisher Provided ID (PPID). Requires `gamObjectReference` to be provided in the configuration. | `true` | ### Configuration example @@ -81,6 +82,7 @@ pbjs.setConfig({ sourceMetaData: "123.123.123.123", // Optional parameter sourceMetaDataExternal: 123456, // Optional parameter reportMethod: "GET", // Optional parameter + shouldSetPPID: true, // Optional parameter additionalParameters: [ // Optional parameter { parameterName: "abc",