Skip to content

Commit 530f02b

Browse files
bretgjeanstemp
andauthored
adding deviceAccess flag and TCF2 (#1857)
* adding deviceAccess flag and TCF2 * moved tcf2 blog post to separate PR * edits * removing defaultGdprScope from this PR * clarifying Confirming which bidders need to update and how to get a bidder on the TCF 1.1 and TCF 2.0 lists. Co-authored-by: Jean Stemp <[email protected]>
1 parent 5b312b2 commit 530f02b

File tree

4 files changed

+156
-28
lines changed

4 files changed

+156
-28
lines changed

_includes/partners.html

+4-4
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
</script>
1818
<div id="memberTableLeader"></div>
1919
<script>
20-
writeDynamicTable({div:"memberTableLeader", data:"memberDataLeader", sort:"rowFirst", maxcols:4, striped: false});
20+
writeDynamicTable({div:"memberTableLeader", data:"memberDataLeader", sort:"rowFirst", maxcols:4, striped: false, fixedHeight: true});
2121
</script>
2222

2323
<div class="tableTitle"><h3>Prebid.org Technology Partner Members</h3></div>
@@ -35,7 +35,7 @@
3535
</script>
3636
<div id="memberTableTech"></div>
3737
<script>
38-
writeDynamicTable({div:"memberTableTech", data:"memberDataTech", sort:"rowFirst", striped: false});
38+
writeDynamicTable({div:"memberTableTech", data:"memberDataTech", sort:"rowFirst", maxcols: 4, striped: false, fixedHeight: true});
3939
</script>
4040

4141
<div class="tableTitle"><h3>Prebid.org Publisher Members</h3></div>
@@ -53,7 +53,7 @@
5353
</script>
5454
<div id="memberTablePub"></div>
5555
<script>
56-
writeDynamicTable({div: "memberTablePub", data: "memberDataPub", sort:"rowFirst", maxcols: 4, striped: false});
56+
writeDynamicTable({div: "memberTablePub", data: "memberDataPub", sort:"rowFirst", maxcols: 4, striped: false, fixedHeight: true});
5757
</script>
5858

5959
<div class="tableTitle"><h3>Prebid.org Community Members</h3></div>
@@ -73,7 +73,7 @@
7373

7474
<div id="memberTableComm"></div>
7575
<script>
76-
writeDynamicTable({div: "memberTableComm", data: "memberDataComm", sort:"rowFirst", striped: false});
76+
writeDynamicTable({div: "memberTableComm", data: "memberDataComm", sort:"rowFirst", maxcols: 4, striped: false, fixedHeight: true});
7777
</script>
7878

7979

assets/js/dynamicTable.js

+19-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
// data is the name of variable containing the data
1111
// sort can be "colFirst" (the default) or "rowFirst"
1212
// maxcols can set a max number of columns
13-
// striped is boolean defining whether to set the table-striped class. defaults to yes.
13+
// striped is boolean defining whether to set the table-striped class. defaults to true.
14+
// fixedHeight is boolean defining whether to set the fixed height class. defaults to false
1415
//
1516
// Structure of the data-array:
1617
// dynamicTableContents[{{x}}]={};
@@ -58,24 +59,36 @@ function writeDynamicTable(args) {
5859

5960
var tbl = document.createElement('table');
6061
tbl.style.width = '100%';
61-
var striped;
62-
if (typeof args.striped === 'undefined') {
63-
striped=true;
62+
var striped=true;
63+
if (typeof args.striped === 'boolean') {
64+
striped=args.striped;
6465
}
6566
if (striped) {
6667
tbl.setAttribute('class', 'table-bordered table-striped centered');
6768
} else {
6869
tbl.setAttribute('class', 'table-bordered centered');
6970
}
71+
var fixedHeight=false;
72+
if (typeof args.fixedHeight === 'boolean') {
73+
fixedHeight=args.fixedHeight;
74+
}
7075
var tbdy = document.createElement('tbody');
7176
tbdy.setAttribute('class','centered');
7277
var idx=0;
7378
for (var r = 0; r < numRows; r++) {
7479
var tr = document.createElement('tr');
75-
tr.setAttribute('class','centeredFixedHeight');
80+
if (fixedHeight) {
81+
tr.setAttribute('class','centeredFixedHeight');
82+
} else {
83+
tr.setAttribute('class','centered');
84+
}
7685
for (var c = 0; c < numCols; c++) {
7786
var td = document.createElement('td');
78-
td.setAttribute('class','centeredFixedHeight');
87+
if (fixedHeight) {
88+
td.setAttribute('class','centeredFixedHeight');
89+
} else {
90+
td.setAttribute('class','centered');
91+
}
7992
if (sortType == "colFirst") {
8093
idx=(r + (c*numRows));
8194
} else {

dev-docs/modules/consentManagement.md

+119-18
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ sidebarType : 1
1515
* TOC
1616
{: toc }
1717

18+
{: .alert.alert-warning :}
19+
Prebid.org is working on updates that will enable support for reading and parsing TCF 2.0 consent strings. See the [blog post](/blog/tcf2) for timelines.
20+
1821
## Overview
1922

2023
This consent management module is designed to support the EU General Data Protection Regulation ([GDPR](https://www.iab.com/topics/consumer-privacy/gdpr/))
@@ -44,13 +47,13 @@ If the timeout period expires or an error from the CMP is thrown, one of these a
4447

4548
## Page Integration
4649

47-
To utilize this module, a CMP compatible with the [IAB 1.1 TCF spec](https://iabeurope.eu/tcf-v1/) needs to be implemented on the site to interact with the user and obtain their consent choices.
50+
To utilize this module, a Consent Management Platform (CMP) compatible with the [IAB TCF v1.1 spec](https://iabeurope.eu/tcf-v1/) or [IAB TCF v2.0 spec](https://iabeurope.eu/tcf-2-0/) needs to be implemented on the site to interact with the user and obtain their consent choices.
4851

4952
Though implementation details for the CMP are not covered by Prebid.org, we do recommend to that you place the CMP code before the Prebid.js code in the head of the page in order to ensure the CMP's framework is loaded before the Prebid code executes.
5053

5154
Once the CMP is implemented, simply include this module into your build and add a `consentManagement` object in the `setConfig()` call. Adapters that support this feature will then be able to retrieve the consent information and incorporate it in their requests.
5255

53-
Here are the parameters supported in the `consentManagement` object:
56+
Here are the parameters supported in the `consentManagement.gdpr` object:
5457

5558
{: .alert.alert-warning :}
5659
Note that versions of Prebid.js before 2.43.0 had a different GDPR configuration. The module is backwards-compatible,
@@ -62,15 +65,70 @@ but we recommend migrating to the new config structure as soon as possible.
6265
| gdpr | `Object` | | |
6366
| gdpr.cmpApi | `string` | The CMP interface that is in use. Supported values are **'iab'** or **'static'**. Static allows integrations where IAB-formatted consent strings are provided in a non-standard way. Default is `'iab'`. | `'iab'` |
6467
| gdpr.timeout | `integer` | Length of time (in milliseconds) to allow the CMP to obtain the GDPR consent string. Default is `10000`. | `10000` |
65-
| gdpr.allowAuctionWithoutConsent | `boolean` | Determines what will happen if obtaining consent information from the CMP fails; either allow the auction to proceed (`true`) or cancel the auction (`false`). Default is `true` | `true` |
66-
| gdpr.consentData | `Object` | An object representing the GDPR consent data being passed directly; only used when cmpApi is 'static'. Default is `undefined`. Not currently supported for US Privacy. | |
68+
| gdpr.allowAuctionWithoutConsent | `boolean` | (TCF v1.1 only) Determines what will happen if obtaining consent information from the CMP fails; either allow the auction to proceed (`true`) or cancel the auction (`false`). Default is `true` | `true` |
69+
| gdpr.consentData | `Object` | An object representing the GDPR consent data being passed directly; only used when cmpApi is 'static'. Default is `undefined`. | |
70+
| gdpr.consentData.getTCData.tcString | `string` | (TCF v2.0 only) Base64url-encoded TCF v2.0 string with segments. | |
71+
| gdpr.consentData.getTCData.gdprApplies | `boolean` | (TCF v2.0 only) Defines whether or not this pageview is in GDPR scope. | |
72+
| gdpr.consentData.getConsentData.gdprApplies | `boolean` | (TCF v1.1 only) Defines whether or not this pageview is in GDPR scope. | |
73+
| gdpr.consentData.getConsentData.hasGlobalScope | `boolean` | (TCF v1.1 only) True if consent data is global, false if it's publisher specific. | |
74+
| gdpr.consentData.getConsentData.consentData | `string` | (TCF v1.1 only) Encoded TCF v1.1 string. | |
75+
| gdpr.consentData.getVendorConsents.metadata | `string` | (TCF v1.1 only) Encoded TCF v1.1 string. | |
6776

6877
{: .alert.alert-info :}
69-
NOTE: The `allowAuctionWithoutConsent` parameter refers to the entire consent string, not to any individual consent option. Prebid.js does not parse the GDPR consent string, so it doesn't know if the user has consented to any particular action.
78+
NOTE: The `allowAuctionWithoutConsent` parameter supported for TCF v1.1 refers to the entire consent string, not to any individual consent option. Prebid.js does not parse the GDPR consent string, so it doesn't know if the user has consented to any particular action.
7079

71-
### Examples
80+
A related parameter is `deviceAccess`, which is at the global level of Prebid.js configuration because it can be used GDPR, CCPA, or custom privacy implementations:
7281

73-
Example 1: GDPR IAB CMP using custom timeout and cancel-auction options.
82+
{: .table .table-bordered .table-striped }
83+
| Param | Type | Description | Example |
84+
| --- | --- | --- | --- |
85+
| deviceAccess | `boolean` | If false, Prebid.js will prevent adapters and modules from reading and setting cookies and HTML local storage. Defaults to `true`. | `false` |
86+
87+
88+
### TCF v2.0 Examples
89+
90+
Example 1: IAB CMP using custom timeout
91+
92+
{% highlight js %}
93+
var pbjs = pbjs || {};
94+
pbjs.que = pbjs.que || [];
95+
pbjs.que.push(function() {
96+
pbjs.setConfig({
97+
consentManagement: {
98+
gdpr: {
99+
cmpApi: 'iab',
100+
timeout: 8000
101+
}
102+
}
103+
});
104+
});
105+
{% endhighlight %}
106+
107+
Example 2: Static CMP using custom data passing.
108+
109+
{% highlight js %}
110+
var pbjs = pbjs || {};
111+
pbjs.que = pbjs.que || [];
112+
pbjs.que.push(function() {
113+
pbjs.setConfig({
114+
consentManagement: {
115+
gdpr: {
116+
cmpApi: 'static',
117+
consentData: {
118+
getTCData: {
119+
tcString: 'COwK6gaOwK6gaFmAAAENAPCAAAAAAAAAAAAAAAAAAAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw',
120+
gdprApplies: true
121+
}
122+
}
123+
}
124+
}
125+
});
126+
});
127+
{% endhighlight %}
128+
129+
### TCF v1.1 Examples
130+
131+
Example 1: IAB CMP using custom timeout and cancel-auction options.
74132

75133
{% highlight js %}
76134
var pbjs = pbjs || {};
@@ -85,7 +143,6 @@ Example 1: GDPR IAB CMP using custom timeout and cancel-auction options.
85143
}
86144
}
87145
});
88-
pbjs.addAdUnits(adUnits);
89146
});
90147
{% endhighlight %}
91148

@@ -114,7 +171,6 @@ Example 2: Static CMP using custom data passing.
114171
}
115172
}
116173
});
117-
pbjs.addAdUnits(adUnits);
118174
});
119175
{% endhighlight %}
120176

@@ -128,6 +184,9 @@ gulp build --modules=consentManagement,bidAdapter1,bidAdapter2
128184

129185
## Adapter Integration
130186

187+
{: .alert.alert-info :}
188+
Prebid.js adapters don't need to change to support TCF v2.0 if they already support TCF 1.1 -- the consent string is passed through the same bidrequest location. The bidder's endpoint, however, will need to change to support TCF v2.0. Once the endpoint supports TCF2, you can update the documentation.md file as described below above the table showing the list of TCF2-compliant bidders.
189+
131190
If you are submitting changes to an adapter to support this approach, please also submit a PR to the [docs repo](https://github.com/prebid/prebid.github.io) to add the `gdpr_supported: true` variable to your respective page in the [bidders directory](https://github.com/prebid/prebid.github.io/tree/master/dev-docs/bidders). **This will ensure that your adapter's name will automatically appear on the list of adapters supporting GDPR.**
132191

133192
### Bidder Adapter GDPR Integration
@@ -204,7 +263,23 @@ getUserSyncs: function(syncOptions, responses, gdprConsent, usPrivacy) {
204263

205264
Depending on your needs, you could include the consent information in a query of your pixel and/or, given the consent choices, determine if you should drop the pixels at all.
206265

207-
## Publishers not using an IAB-Compliant CMP
266+
## Publisher Scenarios
267+
268+
### Page Control of Consented Activities
269+
270+
Page JavaScript can prevent Prebid.js from performing various activities that come under the scope of GDPR controls. Since header bidding isn't the only service that falls under GDPR scope, the page may already have parsed the TCF string and stored it.
271+
272+
Here are some things that publishers can do to control various activities:
273+
274+
1. If the user hasn't consented to Purpose 1:
275+
- Set [deviceAccess](/dev-docs/publisher-api-reference.html#setConfig-deviceAccess): false
276+
- Don't enable [userSync](/dev-docs/publisher-api-reference.html#setConfig-Configure-User-Syncing)
277+
- Don't enable [userId](/dev-docs/modules/userId.html) modules
278+
279+
2. If you're working with bidders that don't support GDPR, consider dynamically populating adunits as needed. See the list below for bidders supporting GDPR.
280+
281+
282+
### Publishers Not Using an IAB-Compliant CMP
208283

209284
Prebid.js and much of the ad industry rely on the IAB CMP standard for GDPR support, but there might be some publishers who have implemented a different approach to meeting the privacy rules. Those publishers can utilize Prebid.js and the whole header bidding ecosystem by building a translation layer between their consent method and the IAB method.
210285

@@ -279,7 +354,7 @@ var cmpLoaded; // true if iabConsentData was loaded and processed
279354
})(window, document);
280355
{% endhighlight %}
281356

282-
### Explanation of Parameters
357+
#### Explanation of Parameters
283358

284359
**_iabConsentData_**
285360
For instructions on how to generate the IAB consent string see the [IAB CMP 1.1 Spec](https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework) and [IAB Consent String SDK](https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/tree/master/Consent%20String%20SDK).
@@ -299,26 +374,52 @@ This should be false if there was some error in the consent data; otherwise set
299374
**_cmpLoaded_**
300375
This should be be set to true once the parameters listed above are processed.
301376

302-
## Adapters Supporting GDPR
377+
## Adapters Supporting TCF v1.1:
378+
379+
Bidders on this list have self-declared their TCF 1.1 support in their https://github.com/prebid/prebid.github.io/tree/master/dev-docs/bidders md file by adding `gdpr_supported: true`.
303380

304381
<script src="/assets/js/dynamicTable.js" type="text/javascript"></script>
305382

306383
<script type="text/javascript">
307-
var adaptersSupportingGdpr=[];
384+
var adaptersSupportingGdpr1=[];
308385
var idx_gdpr=0;
309386
{% assign bidder_pages = site.pages | where: "layout", "bidder" %}
310387
{% for item in bidder_pages %}
311388
{% if item.gdpr_supported == true %}
312-
adaptersSupportingGdpr[idx_gdpr]={};
313-
adaptersSupportingGdpr[idx_gdpr].href="/dev-docs/bidders.html#{{item.biddercode}}";
314-
adaptersSupportingGdpr[idx_gdpr].text="{{item.title}}";
389+
adaptersSupportingGdpr1[idx_gdpr]={};
390+
adaptersSupportingGdpr1[idx_gdpr].href="/dev-docs/bidders.html#{{item.biddercode}}";
391+
adaptersSupportingGdpr1[idx_gdpr].text="{{item.title}}";
392+
idx_gdpr++;
393+
{% endif %}
394+
{% endfor %}
395+
</script>
396+
397+
<div id="adaptersTableGdpr1">
398+
<script>
399+
writeDynamicTable({div: "adaptersTableGdpr1", data: "adaptersSupportingGdpr1", sort: "rowFirst", striped: false} );
400+
</script>
401+
</div>
402+
403+
## Adapters Supporting TCF v2.0:
404+
405+
Bidders on this list have self-declared their TCF 2.0 support in their https://github.com/prebid/prebid.github.io/tree/master/dev-docs/bidders md file by adding `tcf2_supported: true`.
406+
407+
<script type="text/javascript">
408+
var adaptersSupportingGdpr2=[];
409+
var idx_gdpr=0;
410+
{% assign bidder_pages = site.pages | where: "layout", "bidder" %}
411+
{% for item in bidder_pages %}
412+
{% if item.tcf2_supported == true %}
413+
adaptersSupportingGdpr2[idx_gdpr]={};
414+
adaptersSupportingGdpr2[idx_gdpr].href="/dev-docs/bidders.html#{{item.biddercode}}";
415+
adaptersSupportingGdpr2[idx_gdpr].text="{{item.title}}";
315416
idx_gdpr++;
316417
{% endif %}
317418
{% endfor %}
318419
</script>
319420

320-
<div id="adaptersTableGdpr">
421+
<div id="adaptersTableGdpr2">
321422
<script>
322-
writeDynamicTable({div: "adaptersTableGdpr", data: "adaptersSupportingGdpr", sort: "rowFirst", striped: false} );
423+
writeDynamicTable({div: "adaptersTableGdpr2", data: "adaptersSupportingGdpr2", sort: "rowFirst", striped: false} );
323424
</script>
324425
</div>

dev-docs/publisher-api-reference.md

+14
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ This page has documentation for the public API methods of Prebid.js.
4242
* [.markWinningBidAsUsed(markBidRequest)](#module_pbjs.markWinningBidAsUsed)
4343
* [.setConfig(options)](#module_pbjs.setConfig)
4444
* [debugging](#setConfig-Debugging)
45+
* [deviceAccess](#setConfig-deviceAcess)
4546
* [bidderTimeout](#setConfig-Bidder-Timeouts)
4647
* [maxRequestsPerOrigin](#setConfig-Max-Requests-Per-Origin)
4748
* [disableAjaxTimeout](#setConfig-Disable-Ajax-Timeout)
@@ -1260,6 +1261,7 @@ See below for usage examples.
12601261
Core config:
12611262

12621263
+ [Debugging](#setConfig-Debugging)
1264+
+ [Device Access](#setConfig-deviceAccess)
12631265
+ [Bidder Timeouts](#setConfig-Bidder-Timeouts)
12641266
+ [Max Requests Per Origin](#setConfig-Max-Requests-Per-Origin)
12651267
+ [Disable Ajax Timeout](#setConfig-Disable-Ajax-Timeout)
@@ -1307,6 +1309,18 @@ pbjs.setConfig({ debug: true });
13071309
{: .alert.alert-warning :}
13081310
Note that turning on debugging for Prebid Server causes most server-side adapters to consider it a test request, meaning that they won't count on reports.
13091311

1312+
<a name="setConfig-deviceAccess" />
1313+
1314+
#### Device Access
1315+
1316+
You can prevent Prebid.js from reading or writing cookies or HTML localstorage by setting this flag:
1317+
1318+
{% highlight js %}
1319+
pbjs.setConfig({ deviceAccess: false });
1320+
{% endhighlight %}
1321+
1322+
This can be useful in GDPR, CCPA, COPPA or other privacy scenarios where a publisher has determined that header bidding should not read from or write the user's device.
1323+
13101324
<a name="setConfig-Bidder-Timeouts" />
13111325

13121326
#### Bidder Timeouts

0 commit comments

Comments
 (0)