diff --git a/modules/rubiconBidAdapter.js b/modules/rubiconBidAdapter.js index 13d41978027..075eabc208e 100644 --- a/modules/rubiconBidAdapter.js +++ b/modules/rubiconBidAdapter.js @@ -206,19 +206,14 @@ export const spec = { gdprApplies = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; } - if (data.regs) { - if (data.regs.ext) { - data.regs.ext.gdpr = gdprApplies; - } else { - data.regs.ext = {gdpr: gdprApplies}; - } - } else { - data.regs = {ext: {gdpr: gdprApplies}}; - } - + utils.deepSetValue(data, 'regs.ext.gdpr', gdprApplies); utils.deepSetValue(data, 'user.ext.consent', bidderRequest.gdprConsent.consentString); } + if (bidderRequest.uspConsent) { + utils.deepSetValue(data, 'regs.ext.us_privacy', bidderRequest.uspConsent); + } + if (bidRequest.userId && typeof bidRequest.userId === 'object' && (bidRequest.userId.tdid || bidRequest.userId.pubcid || bidRequest.userId.lipb)) { utils.deepSetValue(data, 'user.ext.eids', []); @@ -344,6 +339,7 @@ export const spec = { 'p_pos', 'gdpr', 'gdpr_consent', + 'us_privacy', 'rp_schain', 'tpid_tdid', 'tpid_liveintent.com', @@ -471,6 +467,10 @@ export const spec = { data['gdpr_consent'] = bidderRequest.gdprConsent.consentString; } + if (bidderRequest.uspConsent) { + data['us_privacy'] = encodeURIComponent(bidderRequest.uspConsent); + } + // visitor properties if (params.visitor !== null && typeof params.visitor === 'object') { Object.keys(params.visitor).forEach((key) => { @@ -680,7 +680,7 @@ export const spec = { return (adB.cpm || 0.0) - (adA.cpm || 0.0); }); }, - getUserSyncs: function (syncOptions, responses, gdprConsent) { + getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent) { if (!hasSynced && syncOptions.iframeEnabled) { // data is only assigned if params are available to pass to SYNC_ENDPOINT let params = ''; @@ -694,6 +694,10 @@ export const spec = { } } + if (uspConsent) { + params += `${params ? '&' : '?'}us_privacy=${encodeURIComponent(uspConsent)}`; + } + hasSynced = true; return { type: 'iframe', diff --git a/test/spec/modules/rubiconBidAdapter_spec.js b/test/spec/modules/rubiconBidAdapter_spec.js index 68abb7ffb77..c0ed4245cbf 100644 --- a/test/spec/modules/rubiconBidAdapter_spec.js +++ b/test/spec/modules/rubiconBidAdapter_spec.js @@ -186,8 +186,13 @@ describe('the rubicon adapter', function () { } } + function createUspBidderRequest() { + bidderRequest.uspConsent = '1NYN'; + } + function createVideoBidderRequest() { createGdprBidderRequest(true); + createUspBidderRequest(); let bid = bidderRequest.bids[0]; bid.mediaTypes = { @@ -893,6 +898,23 @@ describe('the rubicon adapter', function () { }); }); + describe('USP Consent', function () { + it('should send us_privacy if bidderRequest has a value for uspConsent', function () { + createUspBidderRequest(); + let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + let data = parseQuery(request.data); + + expect(data['us_privacy']).to.equal('1NYN'); + }); + + it('should not send us_privacy if bidderRequest has no uspConsent value', function () { + let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + let data = parseQuery(request.data); + + expect(data['us_privacy']).to.equal(undefined); + }); + }); + describe('first party data', function () { it('should not have any tg_v or tg_i params if all are undefined', function () { let params = { @@ -1285,6 +1307,7 @@ describe('the rubicon adapter', function () { expect(post.rp.target.LIseg[0]).to.equal('segA'); expect(post.rp.target.LIseg[1]).to.equal('segB'); expect(post.regs.ext.gdpr).to.equal(1); + expect(post.regs.ext.us_privacy).to.equal('1NYN'); expect(post).to.have.property('ext').that.is.an('object'); expect(post.ext.prebid.targeting.includewinners).to.equal(true); expect(post.ext.prebid).to.have.property('cache').that.is.an('object') @@ -2302,6 +2325,20 @@ describe('the rubicon adapter', function () { type: 'iframe', url: `${emilyUrl}` }); }); + + it('should pass us_privacy if uspConsent is defined', function () { + expect(spec.getUserSyncs({ iframeEnabled: true }, {}, undefined, '1NYN')).to.deep.equal({ + type: 'iframe', url: `${emilyUrl}?us_privacy=1NYN` + }); + }); + + it('should pass us_privacy after gdpr if both are present', function () { + expect(spec.getUserSyncs({ iframeEnabled: true }, {}, { + consentString: 'foo' + }, '1NYN')).to.deep.equal({ + type: 'iframe', url: `${emilyUrl}?gdpr_consent=foo&us_privacy=1NYN` + }); + }); }); describe('get price granularity', function() {