Skip to content

Commit

Permalink
GPP consent module: phase one release (#9321)
Browse files Browse the repository at this point in the history
* GPP consent module phase 1

* various updates and added test pages

* revise calling CMP, remove provisionalConsent, remove cmpDisplayStatus check, update pbs usersync

* change callback check to be more strict

* update logic on adding gpp data to ortb2

* update gpp metadata
  • Loading branch information
jsnellbaker authored Dec 21, 2022
1 parent 51c984e commit e2cfc18
Show file tree
Hide file tree
Showing 16 changed files with 1,374 additions and 33 deletions.
124 changes: 124 additions & 0 deletions integrationExamples/gpt/gpp_us_hello_world.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<!--
This page calls a single bidder for a single ad slot. It can be considered a "hello world" example for using
Prebid with the Google Publisher Tag.
It also makes a good test page for new adapter PR submissions. Simply set your server's Bid Params object in the
bids array inside the adUnits, and it will use your adapter to load an ad.
NOTE that many ad servers won't send back an ad if the URL is localhost... so you might need to
set an alias in your /etc/hosts file so that you can load this page from a different domain.
-->

<html>

<head>
<script type="text/javascript" data-cmp-ab="1" src="https://cdn.consentmanager.net/delivery/semiautomatic.js"
data-cmp-cdid="599af61faf55" data-cmp-host="delivery.consentmanager.net" data-cmp-cdn="cdn.consentmanager.net" data-cmp-codesrc="1"></script>


<script async src="../../build/dev/prebid.js"></script>
<script async src="https://www.googletagservices.com/tag/js/gpt.js"></script>
<script>
var FAILSAFE_TIMEOUT = 3300;
var PREBID_TIMEOUT = 1000;

var adUnits = [{
code: 'div-gpt-ad-1460505748561-0',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]],
}
},
// Replace this object to test a new Adapter!
bids: [{
bidder: 'appnexus',
params: {
placementId: 13144370
}
}]

}];

var pbjs = pbjs || {};
pbjs.que = pbjs.que || [];

</script>

<script>
var googletag = googletag || {};
googletag.cmd = googletag.cmd || [];
googletag.cmd.push(function () {
googletag.pubads().disableInitialLoad();
});

pbjs.que.push(function () {
pbjs.addAdUnits(adUnits);
pbjs.setConfig({
userSync: {
filterSettings: {
iframe: {
bidders: ['appnexus'],
filter: 'include'
}
}
}
})
pbjs.setConfig({
consentManagement: {
gpp: {
cmpApi: 'iab',
timeout: 5000
},
usp: {
cmpApi: 'static',
consentData: {
getUSPData: {
uspString: '1YYY'
}
}
}
}
})
pbjs.requestBids({
bidsBackHandler: sendAdserverRequest,
timeout: PREBID_TIMEOUT
});
});

function sendAdserverRequest() {
if (pbjs.adserverRequestSent) return;
pbjs.adserverRequestSent = true;
googletag.cmd.push(function () {
pbjs.que.push(function () {
pbjs.setTargetingForGPTAsync();
googletag.pubads().refresh();
});
});
}

setTimeout(function () {
sendAdserverRequest();
}, FAILSAFE_TIMEOUT);

</script>

<script>
googletag.cmd.push(function () {
googletag.defineSlot('/19968336/header-bid-tag-0', [[300, 250], [300, 600]], 'div-gpt-ad-1460505748561-0').addService(googletag.pubads());

googletag.pubads().enableSingleRequest();
googletag.enableServices();
});
</script>
</head>

<body>
<h2>Prebid.js Test</h2>
<h5>Div-1</h5>
<!-- <button onclick="googletag.cmd.push(function () {googletag.pubads().refresh();});">Refresh GAM</button> -->
<div id='div-gpt-ad-1460505748561-0'>
<script type='text/javascript'>
googletag.cmd.push(function () { googletag.display('div-gpt-ad-1460505748561-0'); });
</script>
</div>
</body>

</html>
12 changes: 12 additions & 0 deletions integrationExamples/gpt/gpp_us_hello_world_iframe.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!-- start a locally ran server under a different port than 9999 and run gulp serve.
load this page from the local server to properly replicate loading prebid.js within a 3rd party iframe -->
<html>
<head>
<script type="text/javascript" data-cmp-ab="1" src="https://cdn.consentmanager.net/delivery/autoblocking/599af61faf55.js"
data-cmp-host="delivery.consentmanager.net" data-cmp-cdn="cdn.consentmanager.net" data-cmp-codesrc="1"></script>
</head>
<body>
<iframe style="width: 100%; height: 100%;" src="http://test.localhost:9999/integrationExamples/gpt/gpp_us_hello_world_iframe_subpage.html"></iframe>
</body>
</html>

140 changes: 140 additions & 0 deletions integrationExamples/gpt/gpp_us_hello_world_iframe_subpage.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<!--
This page calls a single bidder for a single ad slot. It can be considered a "hello world" example for using
Prebid with the Google Publisher Tag.
It also makes a good test page for new adapter PR submissions. Simply set your server's Bid Params object in the
bids array inside the adUnits, and it will use your adapter to load an ad.
NOTE that many ad servers won't send back an ad if the URL is localhost... so you might need to
set an alias in your /etc/hosts file so that you can load this page from a different domain.
-->

<html>

<head>
<script async src="../../build/dev/prebid.js"></script>
<script async src="https://www.googletagservices.com/tag/js/gpt.js"></script>
<script>
var FAILSAFE_TIMEOUT = 3300;
var PREBID_TIMEOUT = 1000;

var adUnits = [{
code: 'div-gpt-ad-1460505748561-0',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]],
}
},
// Replace this object to test a new Adapter!
bids: [{
bidder: 'appnexus',
params: {
placementId: 13144370
}
}]

}];

var pbjs = pbjs || {};
pbjs.que = pbjs.que || [];

</script>

<script>
var googletag = googletag || {};
googletag.cmd = googletag.cmd || [];
googletag.cmd.push(function () {
googletag.pubads().disableInitialLoad();
});

pbjs.que.push(function () {
pbjs.addAdUnits(adUnits);
pbjs.setConfig({
userSync: {
filterSettings: {
iframe: {
bidders: ['appnexus'],
filter: 'include'
}
}
}
})
pbjs.setConfig({
debug: true,
consentManagement: {
gpp: {
cmpApi: 'iab',
timeout: 5000
},
usp: {
cmpApi: 'static',
consentData: {
getUSPData: {
uspString: '1YYY'
}
}
}
}
})
pbjs.requestBids({
bidsBackHandler: sendAdserverRequest,
timeout: PREBID_TIMEOUT
});
});

function sendAdserverRequest() {
if (pbjs.adserverRequestSent) return;
pbjs.adserverRequestSent = true;
googletag.cmd.push(function () {
pbjs.que.push(function () {
pbjs.setTargetingForGPTAsync();
googletag.pubads().refresh();
});
});
}

// setTimeout(function () {
// sendAdserverRequest();
// }, FAILSAFE_TIMEOUT);

</script>

<script>
googletag.cmd.push(function () {
googletag.defineSlot('/19968336/header-bid-tag-0', [[300, 250], [300, 600]], 'div-gpt-ad-1460505748561-0').addService(googletag.pubads());

googletag.pubads().enableSingleRequest();
googletag.enableServices();
});
</script>
</head>

<body>
<h2>Prebid.js Test</h2>
<h5>Div-1</h5>
<!-- <button onclick="pbjs.que.push(function() {pbjs.setConfig({
consentManagement: {
gpp: {
cmpApi: 'iab',
timeout: 5000
},
usp: {
cmpApi: 'static',
consentData: {
getUSPData: {
uspString: '1YYY'
}
}
}
}
});
pbjs.requestBids({
bidsBackHandler: sendAdserverRequest,
timeout: PREBID_TIMEOUT
});})">Start Auction</button> -->
<div id='div-gpt-ad-1460505748561-0'>
<script type='text/javascript'>
googletag.cmd.push(function () { googletag.display('div-gpt-ad-1460505748561-0'); });
</script>
</div>
</body>

</html>
25 changes: 23 additions & 2 deletions modules/appnexusBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,18 @@ export const spec = {
payload.us_privacy = bidderRequest.uspConsent;
}

if (bidderRequest?.gppConsent) {
payload.privacy = {
gpp: bidderRequest.gppConsent.gppString,
gpp_sid: bidderRequest.gppConsent.applicableSections
}
} else if (bidderRequest?.ortb2?.regs?.gpp) {
payload.privacy = {
gpp: bidderRequest.ortb2.regs.gpp,
gpp_sid: bidderRequest.ortb2.regs.gpp_sid
}
}

if (bidderRequest && bidderRequest.refererInfo) {
let refererinfo = {
// TODO: are these the correct referer values?
Expand Down Expand Up @@ -424,8 +436,17 @@ export const spec = {
}
},

getUserSyncs: function (syncOptions, responses, gdprConsent) {
if (syncOptions.iframeEnabled && hasPurpose1Consent(gdprConsent)) {
getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent, gppConsent) {
function checkGppStatus(gppConsent) {
// this is a temporary measure to supress usersync in US-based GPP regions
// this logic will be revised when proper signals (akin to purpose1 from TCF2) can be determined for US GPP
if (gppConsent && Array.isArray(gppConsent.applicableSections)) {
return gppConsent.applicableSections.every(sec => typeof sec === 'number' && sec <= 5);
}
return true;
}

if (syncOptions.iframeEnabled && hasPurpose1Consent(gdprConsent) && checkGppStatus(gppConsent)) {
return [{
type: 'iframe',
url: 'https://acdn.adnxs.com/dmp/async_usersync.html'
Expand Down
7 changes: 6 additions & 1 deletion modules/bidViewability.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as events from '../src/events.js';
import CONSTANTS from '../src/constants.json';
import {isFn, logWarn, triggerPixel} from '../src/utils.js';
import {getGlobal} from '../src/prebidGlobal.js';
import adapterManager, {gdprDataHandler, uspDataHandler} from '../src/adapterManager.js';
import adapterManager, {gdprDataHandler, uspDataHandler, gppDataHandler} from '../src/adapterManager.js';
import {find} from '../src/polyfill.js';

const MODULE_NAME = 'bidViewability';
Expand Down Expand Up @@ -44,6 +44,11 @@ export let fireViewabilityPixels = (globalModuleConfig, bid) => {
const uspConsent = uspDataHandler.getConsentData();
if (uspConsent) { queryParams.us_privacy = uspConsent; }

const gppConsent = gppDataHandler.getConsentData();
if (gppConsent) {
// TODO - need to know what to set here for queryParams...
}

bid[BID_VURL_ARRAY].forEach(url => {
// add '?' if not present in URL
if (Object.keys(queryParams).length > 0 && url.indexOf('?') === -1) {
Expand Down
8 changes: 4 additions & 4 deletions modules/consentManagement.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ function lookupIabConsent({onSuccess, onError}) {
const { cmpFrame, cmpFunction } = findCMP();

if (!cmpFrame) {
return onError('CMP not found.');
return onError('TCF2 CMP not found.');
}
// to collect the consent information from the user, we perform two calls to the CMP in parallel:
// first to collect the user's consent choices represented in an encoded string (via getConsentData)
Expand Down Expand Up @@ -314,11 +314,11 @@ export function resetConsentData() {
* @param {{cmp:string, timeout:number, allowAuctionWithoutConsent:boolean, defaultGdprScope:boolean}} config required; consentManagement module config settings; cmp (string), timeout (int), allowAuctionWithoutConsent (boolean)
*/
export function setConsentConfig(config) {
// if `config.gdpr` or `config.usp` exist, assume new config format.
// if `config.gdpr`, `config.usp` or `config.gpp` exist, assume new config format.
// else for backward compatability, just use `config`
config = config && (config.gdpr || config.usp ? config.gdpr : config);
config = config && (config.gdpr || config.usp || config.gpp ? config.gdpr : config);
if (!config || typeof config !== 'object') {
logWarn('consentManagement config not defined, exiting consent manager');
logWarn('consentManagement (gdpr) config not defined, exiting consent manager');
return;
}
if (isStr(config.cmpApi)) {
Expand Down
Loading

0 comments on commit e2cfc18

Please sign in to comment.