From 66ddef84974fb5e76c94a1ad18d42de2f5f7f4f5 Mon Sep 17 00:00:00 2001 From: ym-ainiguez Date: Mon, 27 Jul 2026 11:25:59 -0700 Subject: [PATCH 1/2] Yieldmo Bid Adapter: recover tdid/pubcid/criteoId from userIdAsEids getId() read ids off the legacy bid.userId object, which Prebid removed in 10.0.0 (prebid/Prebid.js#13253) in favor of userIdAsEids. On 10+ that made the adapter silently stop sending the tdid, pubcid and cri_prebid params on the banner request, degrading exchange-side paths that key on them (TTD real-time enrichment, internal pubcid, partner-id cookie match). Fall back to reading each id from userIdAsEids by source (adserver.org, pubcid.org, criteo.com) when bid.userId is absent, preferring the legacy object when present. Restores parity with 9.x on Prebid 10+. Refs PS-7862. Co-Authored-By: Claude Opus 4.8 (1M context) --- modules/yieldmoBidAdapter.js | 27 ++++++++++++- test/spec/modules/yieldmoBidAdapter_spec.js | 43 +++++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/modules/yieldmoBidAdapter.js b/modules/yieldmoBidAdapter.js index f606194e132..b834bf0dc57 100644 --- a/modules/yieldmoBidAdapter.js +++ b/modules/yieldmoBidAdapter.js @@ -389,13 +389,36 @@ function getPageDescription() { } /** - * Gets an id from the userId object if it exists + * EID source for each legacy `bid.userId` key this adapter reads, so those ids + * can be recovered from `userIdAsEids` on Prebid 10+, where the `bid.userId` + * object was removed (prebid/Prebid.js#13253, first shipped in 10.0.0). Without + * this the tdid/pubcid/cri_prebid request params silently stop being sent. + */ +const EID_SOURCE_BY_USER_ID = { + pubcid: 'pubcid.org', + tdid: 'adserver.org', + criteoId: 'criteo.com', +}; + +/** + * Gets an id previously read from the (now-removed) `bid.userId` object. + * Prefers the legacy object when present (pre-Prebid 10); otherwise falls back + * to the matching source in `userIdAsEids`. * @param {*} request * @param {*} idType * @returns an id if there is one, or undefined */ function getId(request, idType) { - return (typeof deepAccess(request, 'userId') === 'object') ? request.userId[idType] : undefined; + const legacyUserId = deepAccess(request, 'userId'); + if (typeof legacyUserId === 'object' && legacyUserId != null && legacyUserId[idType] != null) { + return legacyUserId[idType]; + } + const source = EID_SOURCE_BY_USER_ID[idType]; + if (source) { + const eid = (getEids(request) || []).find(e => e && e.source === source); + return deepAccess(eid, 'uids.0.id'); + } + return undefined; } /** diff --git a/test/spec/modules/yieldmoBidAdapter_spec.js b/test/spec/modules/yieldmoBidAdapter_spec.js index 4f4454c17ae..af9ad9273d5 100644 --- a/test/spec/modules/yieldmoBidAdapter_spec.js +++ b/test/spec/modules/yieldmoBidAdapter_spec.js @@ -267,6 +267,49 @@ describe('YieldmoAdapter', function () { expect(buildAndGetData([criteoIdBid]).cri_prebid).to.deep.equal(criteoId); }); + // Prebid 10+ removed the legacy bid.userId object (prebid/Prebid.js#13253), + // leaving only userIdAsEids. tdid/pubcid/cri_prebid must be recovered from + // there so they keep being sent. + describe('userIdAsEids fallback (Prebid 10+, no bid.userId)', function () { + const eidsOnlyBid = (extraEids = []) => mockBannerBid({ + crumbs: undefined, + userId: undefined, + userIdAsEids: [ + { source: 'pubcid.org', uids: [{ id: 'eid_pubcid', atype: 1 }] }, + { source: 'adserver.org', uids: [{ id: 'eid_tdid', atype: 1, ext: { rtiPartner: 'TDID' } }] }, + { source: 'criteo.com', uids: [{ id: 'eid_criteo', atype: 1 }] }, + ...extraEids, + ], + }); + + it('should read tdid from userIdAsEids adserver.org', function () { + expect(buildAndGetData([eidsOnlyBid()]).tdid).to.equal('eid_tdid'); + }); + + it('should read pubcid from userIdAsEids pubcid.org', function () { + expect(buildAndGetData([eidsOnlyBid()]).pubcid).to.equal('eid_pubcid'); + }); + + it('should read criteoId from userIdAsEids criteo.com', function () { + expect(buildAndGetData([eidsOnlyBid()]).cri_prebid).to.equal('eid_criteo'); + }); + + it('should prefer the legacy bid.userId object when both are present', function () { + const bid = eidsOnlyBid(); + bid.userId = { tdid: 'legacy_tdid' }; + expect(buildAndGetData([bid]).tdid).to.equal('legacy_tdid'); + }); + + it('should omit an id whose source is absent from userIdAsEids', function () { + const bid = mockBannerBid({ + crumbs: undefined, + userId: undefined, + userIdAsEids: [{ source: 'pubcid.org', uids: [{ id: 'eid_pubcid', atype: 1 }] }], + }); + expect(buildAndGetData([bid])).to.not.have.property('tdid'); + }); + }); + it('should add gdpr information to request if available', () => { const gdprConsent = { consentString: 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==', From 9a82269bb817f506354237ee546751345ba97187 Mon Sep 17 00:00:00 2001 From: ym-ainiguez Date: Mon, 27 Jul 2026 12:22:04 -0700 Subject: [PATCH 2/2] Yieldmo Bid Adapter: add real Yahoo userIdAsEids regression fixture Adds a test built from a live getUserIdsAsEids() capture on www.yahoo.com (Prebid 9.53.2): a 13-source blob with a single adserver.org entry tagged rtiPartner TDID, a pubcid.org, no criteo, and 11 sources never read as flat params. Asserts tdid/pubcid are recovered from userIdAsEids on Prebid 10+, that cri_prebid is omitted (no criteo id), and that every EID source is still forwarded via the eids param. Refs PS-7862. Co-Authored-By: Claude Opus 4.8 (1M context) --- test/spec/modules/yieldmoBidAdapter_spec.js | 29 +++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/spec/modules/yieldmoBidAdapter_spec.js b/test/spec/modules/yieldmoBidAdapter_spec.js index af9ad9273d5..4f30dc1f5f3 100644 --- a/test/spec/modules/yieldmoBidAdapter_spec.js +++ b/test/spec/modules/yieldmoBidAdapter_spec.js @@ -308,6 +308,35 @@ describe('YieldmoAdapter', function () { }); expect(buildAndGetData([bid])).to.not.have.property('tdid'); }); + + // Real getUserIdsAsEids() capture from www.yahoo.com (Prebid 9.53.2): a + // 13-source blob with a single adserver.org entry tagged rtiPartner TDID, a + // pubcid.org, no criteo, plus 11 sources we never read as flat params. + // Verifies flat tdid/pubcid are recovered on 10+ and every source still ships + // via the `eids` param. + it('should recover pubcid/tdid from a real Yahoo userIdAsEids blob and forward all sources', function () { + const yahooEids = [ + { source: 'yahoo.com', uids: [{ id: 'ceKGMBMyiD_y9Hiy3yEezGpqPWhG9vckE9uQ9dXvzZ7YH5B3OcU3GkuAGulWrJrGMqumCS4bkIWCl_HKMsb2eQ', atype: 3 }] }, + { source: 'liveramp.com', uids: [{ id: 'ApoINPkmDal1SZ-1eFryc322FuBMuiTIfa0n83qkZ9d4TmmF2yjDwWNFt0rOB2DBaH5YnHs', atype: 3 }] }, + { source: 'liveintent.com', uids: [{ id: '31-AEQ3i4A7U6Q/VmkQW8HMRDb69Hc4Dmb3d9Vw5OujdEhuKayNFArmrWkjwcXZsaWltfVm1zsQVPR6lhgSdD4H6PLANZWX8wE7ctQxbQuxYgvwBQXrbQW4', atype: 3 }] }, + { source: 'liveintent.triplelift.com', uids: [{ id: '3039651338209079102359', atype: 3, ext: { provider: 'liveintent.com' } }] }, + { source: 'rubiconproject.com', uids: [{ id: 'MEDJJCH8-O-IKN8', atype: 3, ext: { provider: 'liveintent.com' } }] }, + { source: 'liveintent.indexexchange.com', uids: [{ id: 'aJ-V4sAoIlYAKl2pAwiuIwAA&2037', atype: 3, ext: { provider: 'liveintent.com' } }] }, + { source: 'openx.net', uids: [{ id: '7a105d7c-4708-4c2d-a3ba-1e795e46983e', atype: 3, ext: { provider: 'liveintent.com' } }] }, + { source: 'pubmatic.com', uids: [{ id: '4235B560-BD45-4F77-9695-19B7846C1E31', atype: 3, ext: { provider: 'liveintent.com' } }] }, + { source: 'liveintent.sovrn.com', uids: [{ id: 'LLFyABZHZ8flvu7cQ-Giva3O', atype: 3, ext: { provider: 'liveintent.com' } }] }, + { source: 'liveintent.sonobi.com', uids: [{ id: '9706c68f-27f2-4424-af37-ab315995f8b0', atype: 3, ext: { provider: 'liveintent.com' } }] }, + { source: 'liveintent.unrulymedia.com', uids: [{ id: 'RX-1927b623-5cc4-4212-b089-32380b081397-005', atype: 3, ext: { provider: 'liveintent.com' } }] }, + { source: 'pubcid.org', uids: [{ id: '41137366-b187-4188-bd07-7e858ac15a9b', atype: 1 }] }, + { source: 'adserver.org', uids: [{ id: '44d89fb7-c8f6-4c5d-913f-d41707bd4511', atype: 1, ext: { rtiPartner: 'TDID' } }], inserter: 'adserver.org', matcher: 'adserver.org', mm: 4 }, + ]; + const data = buildAndGetData([mockBannerBid({ crumbs: undefined, userId: undefined, userIdAsEids: yahooEids })]); + expect(data.pubcid).to.equal('41137366-b187-4188-bd07-7e858ac15a9b'); + expect(data.tdid).to.equal('44d89fb7-c8f6-4c5d-913f-d41707bd4511'); + expect(data).to.not.have.property('cri_prebid'); + // every EID source is still forwarded intact via the eids param + expect(JSON.parse(data.eids).map(e => e.source)).to.have.members(yahooEids.map(e => e.source)); + }); }); it('should add gdpr information to request if available', () => {