Skip to content

Commit

Permalink
PubMatic bid adapter to support CCPA/USP (prebid#4533)
Browse files Browse the repository at this point in the history
* added support for pubcommon, digitrust, id5id

* added support for IdentityLink

* changed the source for id5

* added unit test cases

* changed source param for identityLink

* added CCPA/USP support in PubMatic adapter
  • Loading branch information
pm-harshad-mane authored and afewcc committed Dec 10, 2019
1 parent d6a548f commit 0c2f567
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 1 deletion.
12 changes: 11 additions & 1 deletion modules/pubmaticBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,11 @@ export const spec = {
};
}

// CCPA
if (bidderRequest && bidderRequest.uspConsent) {
utils.deepSetValue(payload, 'regs.ext.us_privacy', bidderRequest.uspConsent);
}

// coppa compliance
if (config.getConfig('coppa') === true) {
utils.deepSetValue(payload, 'regs.coppa', 1);
Expand Down Expand Up @@ -1012,7 +1017,7 @@ export const spec = {
/**
* Register User Sync.
*/
getUserSyncs: (syncOptions, responses, gdprConsent) => {
getUserSyncs: (syncOptions, responses, gdprConsent, uspConsent) => {
let syncurl = USYNCURL + publisherId;

// Attaching GDPR Consent Params in UserSync url
Expand All @@ -1021,6 +1026,11 @@ export const spec = {
syncurl += '&gdpr_consent=' + encodeURIComponent(gdprConsent.consentString || '');
}

// CCPA
if (uspConsent) {
syncurl += '&us_privacy=' + encodeURIComponent(uspConsent);
}

// coppa compliance
if (config.getConfig('coppa') === true) {
syncurl += '&coppa=1';
Expand Down
109 changes: 109 additions & 0 deletions test/spec/modules/pubmaticBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -982,6 +982,43 @@ describe('PubMatic adapter', function () {
expect(data.imp[0].ext.pmZoneId).to.equal(bidRequests[0].params.pmzoneid.split(',').slice(0, 50).map(id => id.trim()).join()); // pmzoneid
});

it('Request params check with USP/CCPA Consent', function () {
let bidRequest = {
uspConsent: '1NYN'
};
let request = spec.buildRequests(bidRequests, bidRequest);
let data = JSON.parse(request.data);
expect(data.regs.ext.us_privacy).to.equal('1NYN');// USP/CCPAs
expect(data.at).to.equal(1); // auction type
expect(data.cur[0]).to.equal('USD'); // currency
expect(data.site.domain).to.be.a('string'); // domain should be set
expect(data.site.page).to.equal(bidRequests[0].params.kadpageurl); // forced pageURL
expect(data.site.publisher.id).to.equal(bidRequests[0].params.publisherId); // publisher Id
expect(data.user.yob).to.equal(parseInt(bidRequests[0].params.yob)); // YOB
expect(data.user.gender).to.equal(bidRequests[0].params.gender); // Gender
expect(data.device.geo.lat).to.equal(parseFloat(bidRequests[0].params.lat)); // Latitude
expect(data.device.geo.lon).to.equal(parseFloat(bidRequests[0].params.lon)); // Lognitude
expect(data.user.geo.lat).to.equal(parseFloat(bidRequests[0].params.lat)); // Latitude
expect(data.user.geo.lon).to.equal(parseFloat(bidRequests[0].params.lon)); // Lognitude
expect(data.ext.wrapper.wv).to.equal($$REPO_AND_VERSION$$); // Wrapper Version
expect(data.ext.wrapper.transactionId).to.equal(bidRequests[0].transactionId); // Prebid TransactionId
expect(data.ext.wrapper.wiid).to.equal(bidRequests[0].params.wiid); // OpenWrap: Wrapper Impression ID
expect(data.ext.wrapper.profile).to.equal(parseInt(bidRequests[0].params.profId)); // OpenWrap: Wrapper Profile ID
expect(data.ext.wrapper.version).to.equal(parseInt(bidRequests[0].params.verId)); // OpenWrap: Wrapper Profile Version ID

expect(data.imp[0].id).to.equal(bidRequests[0].bidId); // Prebid bid id is passed as id
expect(data.imp[0].bidfloor).to.equal(parseFloat(bidRequests[0].params.kadfloor)); // kadfloor
expect(data.imp[0].tagid).to.equal('/15671365/DMDemo'); // tagid
expect(data.imp[0].banner.w).to.equal(300); // width
expect(data.imp[0].banner.h).to.equal(250); // height
expect(data.imp[0].ext.pmZoneId).to.equal(bidRequests[0].params.pmzoneid.split(',').slice(0, 50).map(id => id.trim()).join()); // pmzoneid

// second request without USP/CCPA
let request2 = spec.buildRequests(bidRequests, {});
let data2 = JSON.parse(request2.data);
expect(data2.regs).to.equal(undefined);// USP/CCPAs
});

it('Request should have digitrust params', function() {
window.DigiTrust = {
getUser: function () {
Expand Down Expand Up @@ -2444,5 +2481,77 @@ describe('PubMatic adapter', function () {
expect(response[0].mediaType).to.equal('native');
});
});

describe('getUserSyncs', function() {
const syncurl = 'https://ads.pubmatic.com/AdServer/js/showad.js#PIX&kdntuid=1&p=5670';
let sandbox;
beforeEach(function () {
sandbox = sinon.sandbox.create();
});
afterEach(function() {
sandbox.restore();
})

it('execute only if iframeEnabled', function() {
expect(spec.getUserSyncs({ iframeEnabled: true }, {}, undefined, undefined)).to.deep.equal([{
type: 'iframe', url: syncurl
}]);
expect(spec.getUserSyncs({ iframeEnabled: false }, {}, undefined, undefined)).to.equal(undefined);
});

it('CCPA/USP', function() {
expect(spec.getUserSyncs({ iframeEnabled: true }, {}, undefined, '1NYN')).to.deep.equal([{
type: 'iframe', url: `${syncurl}&us_privacy=1NYN`
}]);
});

it('GDPR', function() {
expect(spec.getUserSyncs({ iframeEnabled: true }, {}, {gdprApplies: true, consentString: 'foo'}, undefined)).to.deep.equal([{
type: 'iframe', url: `${syncurl}&gdpr=1&gdpr_consent=foo`
}]);
expect(spec.getUserSyncs({ iframeEnabled: true }, {}, {gdprApplies: false, consentString: 'foo'}, undefined)).to.deep.equal([{
type: 'iframe', url: `${syncurl}&gdpr=0&gdpr_consent=foo`
}]);
expect(spec.getUserSyncs({ iframeEnabled: true }, {}, {gdprApplies: true, consentString: undefined}, undefined)).to.deep.equal([{
type: 'iframe', url: `${syncurl}&gdpr=1&gdpr_consent=`
}]);
});

it('COPPA: true', function() {
sandbox.stub(config, 'getConfig').callsFake(key => {
const config = {
'coppa': true
};
return config[key];
});
expect(spec.getUserSyncs({ iframeEnabled: true }, {}, undefined, undefined)).to.deep.equal([{
type: 'iframe', url: `${syncurl}&coppa=1`
}]);
});

it('COPPA: false', function() {
sandbox.stub(config, 'getConfig').callsFake(key => {
const config = {
'coppa': false
};
return config[key];
});
expect(spec.getUserSyncs({ iframeEnabled: true }, {}, undefined, undefined)).to.deep.equal([{
type: 'iframe', url: `${syncurl}`
}]);
});

it('GDPR + COPPA:true + CCPA/USP', function() {
sandbox.stub(config, 'getConfig').callsFake(key => {
const config = {
'coppa': true
};
return config[key];
});
expect(spec.getUserSyncs({ iframeEnabled: true }, {}, {gdprApplies: true, consentString: 'foo'}, '1NYN')).to.deep.equal([{
type: 'iframe', url: `${syncurl}&gdpr=1&gdpr_consent=foo&us_privacy=1NYN&coppa=1`
}]);
});
});
});
});

0 comments on commit 0c2f567

Please sign in to comment.