|
| 1 | +## Overview |
| 2 | +Optable module operates using a DCN backend API. Please contact your account manager to get started. |
| 3 | + |
| 4 | +The optable-targeting module enriches an incoming OpenRTB request by adding to the `user.eids` and `user.data` |
| 5 | +objects. Under the hood the module extracts PPIDs (publisher provided IDs) from the incoming request's `user.ext.eids`, |
| 6 | +and also if present sha256-hashed email, sha256-hashed phone, zip or Optable Visitor ID provided correspondingly in the |
| 7 | +`user.ext.optable.email`, `.phone`, `.zip`, `.vid` fields (a full list of IDs is given in a table below). These IDs are |
| 8 | +sent as input to the Targeting API. The received response data is used to enrich the OpenRTB request and response. |
| 9 | +Targeting API endpoint is configurable per publisher. |
| 10 | + |
| 11 | +## Setup |
| 12 | + |
| 13 | +### Execution Plan |
| 14 | + |
| 15 | +This module runs at two stages: |
| 16 | + |
| 17 | +* Processed Auction Request: to enrich `user.eids` and `user.data`. |
| 18 | +* Auction Response: to inject ad server targeting. |
| 19 | + |
| 20 | +We recommend defining the execution plan in the account config so the module is only invoked for specific accounts. See |
| 21 | +below for an example. |
| 22 | + |
| 23 | +### Global Config |
| 24 | + |
| 25 | +There is no host-company level config for this module. |
| 26 | + |
| 27 | +### Account-Level Config |
| 28 | + |
| 29 | +To start using current module in PBS-Java you have to enable module and add |
| 30 | +`optable-targeting-processed-auction-request-hook` and `optable-targeting-auction-response-hook` into hooks execution |
| 31 | +plan inside your config file: |
| 32 | +Here's a general template for the account config used in PBS-Java: |
| 33 | + |
| 34 | +```yaml |
| 35 | +hooks: |
| 36 | + optable-targeting: |
| 37 | + enabled: true |
| 38 | + host-execution-plan: > |
| 39 | + { |
| 40 | + "endpoints": { |
| 41 | + "/openrtb2/auction": { |
| 42 | + "stages": { |
| 43 | + "processed-auction-request": { |
| 44 | + "groups": [ |
| 45 | + { |
| 46 | + "timeout": 100, |
| 47 | + "hook-sequence": [ |
| 48 | + { |
| 49 | + "module-code": "optable-targeting", |
| 50 | + "hook-impl-code": "optable-targeting-processed-auction-request-hook" |
| 51 | + } |
| 52 | + ] |
| 53 | + } |
| 54 | + ] |
| 55 | + }, |
| 56 | + "auction-response": { |
| 57 | + "groups": [ |
| 58 | + { |
| 59 | + "timeout": 10, |
| 60 | + "hook-sequence": [ |
| 61 | + { |
| 62 | + "module-code": "optable-targeting", |
| 63 | + "hook-impl-code": "optable-targeting-auction-response-hook" |
| 64 | + } |
| 65 | + ] |
| 66 | + } |
| 67 | + ] |
| 68 | + } |
| 69 | + } |
| 70 | + } |
| 71 | + } |
| 72 | + } |
| 73 | +``` |
| 74 | +
|
| 75 | +Sample module enablement configuration in JSON and YAML formats: |
| 76 | +
|
| 77 | +```json |
| 78 | +{ |
| 79 | + "modules": |
| 80 | + { |
| 81 | + "optable-targeting": |
| 82 | + { |
| 83 | + "api-endpoint": "endpoint", |
| 84 | + "api-key": "key", |
| 85 | + "timeout": 50, |
| 86 | + "ppid-mapping": { |
| 87 | + "pubcid.org": "c" |
| 88 | + }, |
| 89 | + "adserver-targeting": false |
| 90 | + } |
| 91 | + } |
| 92 | +} |
| 93 | +``` |
| 94 | + |
| 95 | +```yaml |
| 96 | + modules: |
| 97 | + optable-targeting: |
| 98 | + api-endpoint: endpoint |
| 99 | + api-key: key |
| 100 | + timeout: 50 |
| 101 | + ppid-mapping: { |
| 102 | + "pubcid.org": "c" |
| 103 | + } |
| 104 | + adserver-targeting: false |
| 105 | +``` |
| 106 | +
|
| 107 | +### Timeout considerations |
| 108 | +
|
| 109 | +The timeout value specified in the execution plan for the `processed-auction-request` hook is very important to be |
| 110 | +picked such that the hook has enough time to make a roundtrip to Optable Targeting Edge API over HTTP. |
| 111 | + |
| 112 | +**Note:** Do not confuse hook timeout value with the module timeout parameter which is optional. The hook timeout value |
| 113 | +would depend on the cloud/region where the PBS instance is hosted and the latency to reach the Optable's servers. This |
| 114 | +will need to be verified experimentally upon deployment. |
| 115 | + |
| 116 | +The timeout value for the `auction-response` can be set to 10 ms - usually it will be sub-millisecond time as there are |
| 117 | +no HTTP calls made in this hook - Optable-specific keywords are cached on the `processed-auction-request` stage and |
| 118 | +retrieved from the module invocation context later. |
| 119 | + |
| 120 | +## Module Configuration Parameters for PBS-Java |
| 121 | + |
| 122 | +The parameter names are specified with full path using dot-notation. F.e. `section-name` .`sub-section` .`param-name` |
| 123 | +would result in this nesting in the JSON configuration: |
| 124 | + |
| 125 | +```json |
| 126 | +{ |
| 127 | + "section-name": { |
| 128 | + "sub-section": { |
| 129 | + "param-name": "param-value" |
| 130 | + } |
| 131 | + } |
| 132 | +} |
| 133 | +``` |
| 134 | + |
| 135 | + |
| 136 | +| Param Name | Required | Type | Default value | Description | |
| 137 | +|:-------------------|:---------|:--------|:---------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |
| 138 | +| api-endpoint | yes | string | none | Optable Targeting Edge API endpoint URL, required | |
| 139 | +| api-key | no | string | none | If the API is protected with a key - this param needs to be specified to be sent in the auth header | |
| 140 | +| ppid-mapping | no | map | none | This specifies PPID source (`user.ext.eids[].source`) to a custom identifier prefix mapping, f.e. `{"example.com" : "c"}`. See the section on ID Mapping below for more detail. | |
| 141 | +| adserver-targeting | no | boolean | false | If set to true - will add the Optable-specific adserver targeting keywords into the PBS response for every `seatbid[].bid[].ext.prebid.targeting` | |
| 142 | +| timeout | no | integer | false | A soft timeout (in ms) sent as a hint to the Targeting API endpoint to limit the request times to Optable's external tokenizer services | |
| 143 | +| id-prefix-order | no | string | none | An optional string of comma separated id prefixes that prioritizes and specifies the order in which ids are provided to Targeting API in a query string. F.e. "c,c1,id5" will guarantee that Targeting API will see id=c:...,c1:...,id5:... if these ids are provided. id-prefixes not mentioned in this list will be added in arbitrary order after the priority prefix ids. This affects Targeting API processing logic | |
| 144 | + |
| 145 | +## ID Mapping |
| 146 | + |
| 147 | +Internally the module sends requests to Optable Targeting API. The output of Targeting API is used to enrich the request |
| 148 | +and response. The below table describes the parameters that the module automatically fetches from OpenRTB request and |
| 149 | +then sends to the Targeting API. The module will use a prefix as specified in the table to prepend the corresponding ID |
| 150 | +value when sending it to the Targeting API in the form `id=prefix:value`. |
| 151 | + |
| 152 | +See [Optable documentation](https://docs.optable.co/optable-documentation/dmp/reference/identifier-types#type-prefixes) |
| 153 | +on identifier types. Targeting API accepts multiple id parameters - and their order may affect the results, thus |
| 154 | +`id-prefix-order` specifies the order of the ids. |
| 155 | + |
| 156 | + |
| 157 | +| Identifier Type | OpenRTB field | ID Type Prefix | |
| 158 | +|--------------------------------------------------------------------------------|-----------------------------------------------------------------------|------------------------------------------| |
| 159 | +| Email Address | `user.ext.optable.email` | `e:` | |
| 160 | +| Phone Number | `user.ext.optable.phone` | `p:` | |
| 161 | +| Postal Code | `user.ext.optable.zip` | `z:` | |
| 162 | +| IPv4 Address | `device.ip` | ~~i4:~~ Sent as `X-Forwarded-For` header | |
| 163 | +| IPv6 Address | `device.ipv6` | ~~i6:~~ Sent as `X-Forwarded-For` header | |
| 164 | +| Apple IDFA | `device.ifa if lcase(device.os) contains 'ios' and device.lmt!=1` | `a:` | |
| 165 | +| Google GAID | `device.ifa if lcase(device.os) contains 'android' and device.lmt!=1` | `g:` | |
| 166 | +| Roku RIDA | `device.ifa if lcase(device.os) contains 'roku' and device.lmt!=1` | `r:` | |
| 167 | +| Samsung TV TIFA | `device.ifa if lcase(device.os) contains 'tizen' and device.lmt!=1` | `s:` | |
| 168 | +| Amazon Fire AFAI | `device.ifa if lcase(device.os) contains 'fire' and device.lmt!=1` | `f:` | |
| 169 | +| [NetID](https://docs.prebid.org/dev-docs/modules/userid-submodules/netid.html) | `user.ext.eids[].uids[0] when user.ext.eids[].source="netid.de"` | `n:` | |
| 170 | +| [ID5](https://docs.prebid.org/dev-docs/modules/userid-submodules/id5.html) | `user.ext.eids[].uids[0] when user.ext.eids[].source="id5-sync.com"` | `id5:` | |
| 171 | +| [Utiq](https://docs.prebid.org/dev-docs/modules/userid-submodules/utiq.html) | `user.ext.eids[].uids[0] when user.ext.eids[].source="utiq.com"` | `utiq:` | |
| 172 | +| Optable VID | `user.ext.optable.vid` | `v:` | |
| 173 | + |
| 174 | +### Optable input erasure |
| 175 | + |
| 176 | +**Note**: `user.ext.optable.email`, `.phone`, `.zip`, `.vid` fields will be removed by the module from the original |
| 177 | +OpenRTB request before being sent to bidders. |
| 178 | + |
| 179 | +### Publisher Provided IDs (PPID) Mapping |
| 180 | + |
| 181 | +Custom user IDs are sent in the OpenRTB request in the |
| 182 | +[`user.ext.eids[]`](https://github.com/InteractiveAdvertisingBureau/openrtb2.x/blob/main/2.6.md#3227---object-eid-). |
| 183 | +The `ppid-mapping` allows to specify the mapping of a source to one of the custom identifier type prefixes `c`-`c19` - |
| 184 | +see [documentation](https://docs.optable.co/optable-documentation/dmp/reference/identifier-types#type-prefixes), f.e.: |
| 185 | + |
| 186 | +```yaml |
| 187 | +ppid-mapping: {"example.com": "c2", "test.com": "c3"} |
| 188 | +``` |
| 189 | + |
| 190 | +It is also possible to override any of the automatically retrieved `user.ext.eids[]` mentioned in the table above (s.a. |
| 191 | +id5, utiq) so they are mapped to a different prefix. f.e. `id5-sync.com` can be mapped to a prefix other than `id5:`, |
| 192 | +like: |
| 193 | + |
| 194 | +```yaml |
| 195 | +ppid-mapping: {"id5-sync.com": "c1"} |
| 196 | +``` |
| 197 | + |
| 198 | +This will lead to id5 ID supplied as `id=c1:...` to the Targeting API. |
| 199 | + |
| 200 | +## Analytics Tags |
| 201 | + |
| 202 | +The following 2 analytics tags are written by the module: |
| 203 | + |
| 204 | +* `optable-enrich-request` |
| 205 | +* `optable-enrich-response` |
| 206 | + |
| 207 | +The `status` is either `success` or `failure`. Where it is `failure` a `results[0].value.reason` is provided. |
| 208 | +For the `optable-enrich-request` activity the `execution-time` value is logged. |
| 209 | +Example: |
| 210 | + |
| 211 | +```json |
| 212 | +{ |
| 213 | + "analytics": { |
| 214 | + "tags": [ |
| 215 | + { |
| 216 | + "stage": "auction-response", |
| 217 | + "module": "optable-targeting", |
| 218 | + "analyticstags": { |
| 219 | + "activities": [ |
| 220 | + { |
| 221 | + "name": "optable-enrich-request", |
| 222 | + "status": "success", |
| 223 | + "results": [ |
| 224 | + { |
| 225 | + "values": { |
| 226 | + "execution-time": 33 |
| 227 | + } |
| 228 | + } |
| 229 | + ] |
| 230 | + }, |
| 231 | + { |
| 232 | + "name": "optable-enrich-response", |
| 233 | + "status": "success", |
| 234 | + "results": [ |
| 235 | + { |
| 236 | + "values": { |
| 237 | + "reason": "none" |
| 238 | + } |
| 239 | + } |
| 240 | + ] |
| 241 | + } |
| 242 | + ] |
| 243 | + } |
| 244 | + } |
| 245 | + ] |
| 246 | + } |
| 247 | +} |
| 248 | +``` |
| 249 | + |
| 250 | +If `adserver-targeting` was set to `false` in the config `optable-enrich-response` analytics tag is not written. |
| 251 | + |
| 252 | +## Running the demo (PBS-Java) |
| 253 | + |
| 254 | +1. Build the server bundle JAR as described in [Build Project](https://github.com/prebid/prebid-server-java/blob/master/docs/build.md#build-project), e.g. |
| 255 | + |
| 256 | +```bash |
| 257 | +mvn clean package --file extra/pom.xml |
| 258 | +``` |
| 259 | + |
| 260 | +2. In the `sample/configs/prebid-config-optable.yaml` file specify the `api-endpoint` URL of your DCN, f.e.: |
| 261 | + |
| 262 | +```yaml |
| 263 | +api-endpoint: https://example.com/v2/targeting |
| 264 | +``` |
| 265 | + |
| 266 | +3. Start server bundle JAR as described in [Running project](https://github.com/prebid/prebid-server-java/blob/master/docs/run.md#running-project), e.g. |
| 267 | + |
| 268 | +```bash |
| 269 | +java -jar target/prebid-server-bundle.jar --spring.config.additional-location=sample/configs/prebid-config-with-optable.yaml |
| 270 | +``` |
| 271 | + |
| 272 | +4. Run sample request against the server as described in [the sample directory](https://github.com/prebid/prebid-server-java/tree/master/sample), e.g. |
| 273 | + |
| 274 | +```bash |
| 275 | +curl http://localhost:8080/openrtb2/auction --data @extra/modules/optable-targeting/sample-requests/data.json |
| 276 | +``` |
| 277 | + |
| 278 | +5. Observe the `user.eids` and `user.data` objects enriched. |
| 279 | + |
| 280 | +## Maintainer contacts |
| 281 | + |
| 282 | +Any suggestions or questions can be directed to [prebid@optable.co](mailto:prebid@optable.co). |
| 283 | + |
| 284 | +Alternatively please open a new [issue](https://github.com/prebid/prebid-server-java/issues/new) or [pull request](https://github.com/prebid/prebid-server-java/pulls) in this repository. |
0 commit comments