Skip to content

Commit

Permalink
Prebid.js: activity controls (prebid#4501)
Browse files Browse the repository at this point in the history
* Prebid.js: activity controls

* initial pass at wordsmithing

added background and transitions. The example rules need some work IMO. Will tackle that later this week.

* language.

* next round

- added more on rules processing
- annotated examples
- added Further Reading

* adding reference to FAQ

* added rule allow status section

ready for broader review

* Update activity-controls.md

* wordsmithing

updated a few things noticed while working on the PBS version of this doc

* fixed missing allowActivities object

* updated version

---------

Co-authored-by: bretg <bgorsline@gmail.com>
  • Loading branch information
2 people authored and ecdrsvc committed Sep 6, 2023
1 parent ac9aadb commit 9b471ad
Show file tree
Hide file tree
Showing 3 changed files with 296 additions and 0 deletions.
288 changes: 288 additions & 0 deletions dev-docs/activity-controls.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
---
layout: page_v2
title: Activity Controls
description: How to stop Prebid.js from doing things you don't want
sidebarType: 1
pbjs_version: 7.52
---

# Prebid.js Activity Controls
{: .no_toc }

Starting with version 7.52, Prebid.js introduced a centralized control mechanism for privacy-sensitive _activities_ - such as accessing device storage or sharing data with partners.
These controls are intended to serve as building blocks for privacy protection mechanisms, allowing module developers or publishers to directly specify what should be permitted or avoided in any given regulatory environment.

* TOC
{: toc }

## Overview

There are many privacy regulations that Prebid publishers need to accomodate. Prebid supplies [modules](/dev-docs/faq.html#how-does-prebid-support-privacy-regulations) to help Publishers implement their legal policies, but there are scenarios where extra control is needed:

- a Publisher's lawyers want to make a particular exception
- a module hasn't been built for a regulation the Publisher needs to support

### Prebid Is a Toolkit

{: .alert.alert-danger :}
Important: This resource should not be construed as legal advice and Prebid.org makes no guarantees about compliance with any law or regulation. Please note that because every company and its collection, use, and storage of personal data is different, you should seek independent legal advice relating to obligations under European and /or US regulations, including the GDPR, the ePrivacy Directive and CCPA. Only a lawyer can provide you with legal advice specifically tailored to your situation. Nothing in this guide is intended to provide you with, or should be used as a substitute for, legal advice tailored to your business.

1. Get a privacy lawyer.
2. Consider all the privacy regulations your content business is subject to.
3. Come up with a plan.
4. Use Prebid.js modules and these Activity Controls as ways to help implement your privacy plan with respect to header bidding.
5. Let us know if there are tools missing from the Prebid toolkit.

### What is an Activity?

We did an analysis of the things Prebid.js does and identified those related to privacy regulations. We call these things "potentially restricted activities", or just "activities" for short. Here are some:

- Setting a cookie
- Syncing ID cookies
- Transmitting user first party data
- etc.

The [full list of activities Prebid.js supports](#activities) is below.

Think of an activity control as a 'gatekeeper' that makes the decision about whether the activity should be allowed in this specific context:

- Should I allow this cookie to be set for bidderA?
- Should I allow this usersync for bidderB?
- Is it ok for this data to be passed to bidderC and analyticsD?
- etc.

Prebid.js core checks with the Activity Controls to see whether an activity is allowed. The configuration for the activity can come from modules, custom functions in the page, or a rule-based JSON config.

### Example Activity Control

{: .alert.alert-info :}
In this example, bidderX wants to set a cookie through StorageManager, which queries the Activity Control System to determine whether that's allowed. The publisher has set up configuration that specifically enables bidderX to do this.

Here's an example JSON config that disables accessing local storage (including cookies) for everything except the bid adapter `bidderX`:

```
pbjs.setConfig({
allowActivities: {
accessDevice: {
default: false,
rules: [{
condition(params) {
return params.componentName === 'bidderX'
},
allow: true
}]
}`
}
})
```

<a id="config" />

## Configuration

`allowActivities` is a new option to [setConfig](/dev-docs/publisher-api-reference/setConfig.html). It contains a list of activity names -- see the [full list of activities below](#activities). Each activity is an object that can contain these attributes:

{: .table .table-bordered .table-striped }
| Name | Type | Description |
|------|------|-------------|
| `default` | Boolean | Whether the activity should be allowed if no other rule applies. Defaults to true. |
| `rules` | Array of objects | Rules for this activity |
| `rules[].condition` | Function | Condition function to use for this rule; the rule applies only if this returns true. Receives a single object that contains [activity parameters](#parameters) as input. If omitted, the rule always applies. |
| `rules[].allow` | Boolean | Whether the activity should be allowed when this rule applies. Defaults to true. |
| `rules[].priority` | Number | Priority of this rule compared to other rules; a lower number means higher priority. See [note on rule priority](#priority) below. Defaults to 1. |

`Rules` is an array of objects that a publisher can contruct to provide fine-grained control over a given activity. For instance, you could set up a series of rules that says:

- Amongst the bid adapters, BidderA is always allowed to receive user first party data
- Always let analytics adapters receive user first party data
- otherwise, let the active privacy modules decide
- if they refuse to decide, then the overall default is to allow the transmitting of user first party data

There's more about [rules](#parameters) below.

<a id="activities" />

### Activities

Here's the list of the 'potentially restricted activities' that Prebid.js core can restrict for Publishers:

{: .table .table-bordered .table-striped }
| Name | Description | Effect when denied | Additional parameters |
|----------------|-------------|---------------------------|--------------------------------|
| `accessDevice` | A component wants to use device storage | Storage is disabled | [`storageType`](#params-accessDevice) |
| `enrichEids` | A user ID or RTD submodule wants to add user IDs to outgoing requests | User IDs are discarded | None |
| `enrichUfpd` | A Real Time Data (RTD) submodule wants to add user first party data to outgoing requests (`user.data` in ORTB) | User FPD is discarded | None |
| `fetchBids` | A bid adapter wants to participate in an auction | Bidder is removed from the auction | [`configName`](#params-fetchBids) |
| `reportAnalytics` | An analytics adapter is being enabled through `pbjs.enableAnalytics` | Adapter remains disabled | None |
| `syncUser` | A bid adapter wants to fetch a [user sync](/dev-docs/publisher-api-reference/setConfig.html#setConfig-Configure-User-Syncing) | User sync is skipped | [`syncType`, `syncUrl`](#params-syncUser) |
| `transmitEids` | A bid adapter or RTD submodule wants to access and/or transmit user IDs to their endpoint | User IDs are hidden from the component | None |
| `transmitPreciseGeo` | A bid adapter or RTD submodule wants to access and/or transmit precise geolocation data to their endpoint | Component is allowed only 2-digit precision for latitude and longitude | None |
| `transmitUfpd` | A bid adapter or RTD submodule wants to access and/or transmit user FPD to their endpoint | User FPD is hidden from the component | None |

<a id="parameters" />

### Rules

There are three parts to an Activity Control's rule:

1. The priority
2. The condition
3. The allow flag

For example, this rule would allow bidderX to perform the activity if no higher priority rules take precedence.
```
...
rules: [{
priority: 10, // average priority
condition(params) {
return params.componentName === 'bidderX'
},
allow: true
}]
...
```

<a id="priority" />

#### Rule Priority

Activity control rules in Prebid.js can be created by two main sources:

- Publisher `setConfig({allowActivities})` as in the examples shown here. When set this way, rules are consider the highest priority value of 1.
- Modules can set activity control rules, e.g. [usersync](/dev-docs/publisher-api-reference/setConfig.html#setConfig-Configure-User-Syncing), [bidderSettings](/dev-docs/publisher-api-reference/bidderSettings.html), the [GPP](/dev-docs/modules/consentManagementGpp.html) or [GDPR](/dev-docs/modules/gdprEnforcement.html) modules. Rules set by modules have a less urgent priority of 10.

When rules are processed, they are sorted by priority, and all rules of the same priority are considered to happen at the same time. The details:

1. The highest rule priority is 1
2. There's no defined lowest priority other than MAXINT
3. Default priority for rules defined with setConfig is 1. Default priority for other rules is 10.
4. When processing, group the rules by priority
5. Then, in descending order of priority:
1. If any rule that matching the condition defines `allow: false`, the activity is DENIED.
2. Otherwise, if at least one rule that matches the condition defines `allow: true`, the activity is ALLOWED.
3. If any rule matched, break out of the priority loop.
6. If none of rules match, and the activity defines `default: false`, the activity is DENIED.
7. Otherwise, the activity is ALLOWED.

So this means that when `priority` is omitted from `allowActivities` configuration, it acts as an override over other control mechanisms. For example:

```javascript
pbjs.setConfig({
deviceAccess: false, // this would have the effect of disabling device storage, but...
allowActivities: {
accessDevice: {
rules: [
{allow: true} // ... it's overridden by this conditionless rule with default priority of 1
]
}
}
})
```

If a priority number greater than 10 is specified, the rule only takes effect when all other controls have allowed the activity. For example:

```javascript
pbjs.setConfig({
allowActivities: {
accessDevice: {
// the intent here is to disable cookies but allow HTML5 localStorage
// because this defines priority > 10, other controls will be checked first
// e.g. if GDPR is in-scope and there's no consent, this priority 20 rule won't be processed
default: false,
rules: [{
condition({storageType}) {
return storageType === 'html5'
},
allow: true,
priority: 20
}]
}
}
})
```

#### Rule Conditions

A `condition` is a javascript function that receives information about the activity that is about to be performed. If a condition evaluates to true, the `allow` attribute of the rule will be utilized. If there's no condition specified, the rule's `allow` attribute will always be utilized.

These are the parameters available to the condition function:

{: .table .table-bordered .table-striped }
| Name | Type | Available for | Description |
|------|------|-------------|---------------|
| `componentType` | String | All activities | One of: `'bidder'`, `'userId'`, `'rtd'`, `'analytics'`, or `'prebid'`; identifies the type of component (usually a module) that wishes to perform the activity. `'prebid'` is reserved for Prebid core itself and a few "privileged" modules such as the [PBS adapter](/dev-docs/modules/prebidServer.html). |
| `componentName` | String | All activities | Name of the component; this is (depending on the type) either a bidder code, user ID or RTD submodule name, analytics provider code, or module name. |
| `component` | String | All activities | This is always a dot-separated concatenation of `componentType` and `componentName`; for example, with `{componentType: 'bidder', componentName: 'bidderX'}`, `component` is `'bidder.bidderX'`. |
| `adapterCode` | String | All activities | If `componentType` is `'bidder'`, and `componentName` is an [alias](/dev-docs/publisher-api-reference/aliasBidder.html), then `adapterCode` is the bidder code that was aliased; or identical to `componentName` if the bidder is not an alias. This is undefined when the component is not a bidder.|
| `configName` | String | <a id="params-fetchBids" /> `fetchBids` | When the Prebid Server adapter is part of an auction, this is the name given to its [s2s configuration](/dev-docs/modules/prebidServer.md), if any. |
| `storageType` | String | <a id="params-accessDevice" /> `accessDevice` | Either `'html5'` or `'cookie'` - the device storage mechanism being accessed. |
| `syncType` | String | <a id="params-syncUser" /> `syncUser` | Either `'iframe'` or `'image'` - the type of user sync. |
| `syncUrl` | String | `syncUser` | URL of the user sync. |

#### Allow Flag

If the rule's condition matches, this attribute defines whether the rule 'votes' to allow (true) or disallow (false) the activity in question.

As noted in the priority section, **disallow** (false) takes precedence amongst rules at the same priority level.

If `allow` is not defined, the rule is assumed to assert **true** (i.e. allow the activity to take place).

### More examples

#### Always include a particular bidder in auctions

This is similiar to the 'vendor exception' feature of the [GDPR Enforcement Module](/dev-docs/modules/gdprEnforcement.html). This would always allow bidderA to participate in the auction, even without explicit consent in GDPR scenarios. It might indicate, for instance, that this is a 'first party bidder'.

```javascript
pbjs.setConfig({
allowActivities: {
fetchBids: {
rules: [{
condition: ({componentName}) => componentName === 'bidderA',
allow: true
}]
}
}
})
```

#### Disable all user syncs except for specific domains

```javascript
const DOMAINLIST = [
'https://example-domain.org',
'https://other-domain.com',
];

pbjs.setConfig({
allowActivities: {
syncUser: {
default: false,
rules: [{
condition({syncUrl}) {
return DOMAINLIST.find(domain => syncUrl.startsWith(domain))
},
allow: true
}]
}
}
})
```

#### Deny a particular vendor access to user IDs

```javascript
pbjs.setConfig({
allowActivities: {
transmitEids: {
rules: [{
condition: ({componentName}) => componentName === 'exampleVendor',
allow: false,
}]
}
}
})
```

## Further Reading
- [FAQ: How does Prebid.js support privacy regulations](/dev-docs/faq.html#how-does-prebid-support-privacy-regulations)
1 change: 1 addition & 0 deletions dev-docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ To get started, first talk to your lawyers to determine your legal obligations.

After you’ve determined your legal obligations, consider the tools Prebid makes available to publishers so that their pages can determine what actions are needed based on their interpretation of the user’s actions and the company’s policies:

- Consider utilizing an [Activity Control](/dev-docs/activity-controls.html). These are available with Prebid.js 7.48 and may help cover a number of common privacy concerns.
- Turn off Prebid.js usersync:
- [for client-side adapters](/dev-docs/publisher-api-reference/setConfig.html#setConfig-Configure-User-Syncing) - either completely or for certain bidders.
- [for server-side adapters](/dev-docs/modules/prebidServer.html) - override the s2sConfig.syncEndpoint
Expand Down
7 changes: 7 additions & 0 deletions dev-docs/publisher-api-reference/setConfig.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ See below for usage examples.
Core config:

+ [Debugging](#setConfig-Debugging)
+ [Allow activities](#setConfig-allow-activities)
+ [Device Access](#setConfig-deviceAccess)
+ [Bidder Timeouts](#setConfig-Bidder-Timeouts)
+ [Max Requests Per Origin](#setConfig-Max-Requests-Per-Origin)
Expand Down Expand Up @@ -69,6 +70,12 @@ pbjs.setConfig({ debug: true });
{: .alert.alert-warning :}
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.

<a id="setConfig-allow-activities" />

#### Allow activities

Starting since Prebid 7.48, you can prevent Prebid, or individual modules, from performing certain activities through `allowActivities` configuration, which provides fine-grained control over a number privacy-related items, including access to device storage, first party data, or user IDs. For more information, see [activity controls](/dev-docs/activity-controls.html).

<a name="setConfig-deviceAccess" />

#### Device Access
Expand Down

0 comments on commit 9b471ad

Please sign in to comment.