Skip to content

Commit a40a8b2

Browse files
authored
Update prebid helpers to return a partial ortb2 object rather than user.data only (#44)
* Fix various package flags with vulnerabilities * BREAKING: Update prebid helpers to return a partial ortb2 object to merge using mergeConfig
1 parent fc63fcf commit a40a8b2

File tree

8 files changed

+246
-121
lines changed

8 files changed

+246
-121
lines changed

README.md

+4-12
Original file line numberDiff line numberDiff line change
@@ -425,11 +425,11 @@ A working example of both targeting and event witnessing is available in the dem
425425

426426
## Integrating Prebid
427427

428-
The Optable Web SDK can fetch targeting data from a DCN and prepare an audience taxonomy object similar to the one described in [the prebid.js first party data documentation](https://docs.prebid.org/features/firstPartyData.html#segments-and-taxonomy). The `prebidUserDataFromCache()` function returns the object from the targeting data stored by `targeting()` API calls in `LocalStorage`.
428+
The Optable Web SDK can fetch targeting data from a DCN and prepare an audience taxonomy object similar to the one described in [the prebid.js first party data documentation](https://docs.prebid.org/features/firstPartyData.html#segments-and-taxonomy). The `prebidORTB2FromCache()` function returns the object from the targeting data stored by `targeting()` API calls in `LocalStorage`.
429429

430430
### Seller Defined Audiences
431431

432-
The HTML code snippet below shows how `prebidUserDataFromCache()` can be used to retrieve targeting data from the `LocalStorage` administered by the Optable SDK, and write Seller Defined Audiences (SDA) into [prebid.js](https://prebid.org/product-suite/prebid-js/) which is also loaded into the page, using `pbjs.setConfig({ ortb2: { user: { data: [ { ... } ] } } })` as documented in [the prebid.js first party data documentation](https://docs.prebid.org/features/firstPartyData.html#segments-and-taxonomy). The `targeting()` API is also called in order to retrieve and locally store the latest matching activations from `dcn.customer.com/my-site`.
432+
The HTML code snippet below shows how `prebidORTB2FromCache()` can be used to retrieve targeting data from the `LocalStorage` administered by the Optable SDK, and write Seller Defined Audiences (SDA) into [prebid.js](https://prebid.org/product-suite/prebid-js/) which is also loaded into the page, using `pbjs.mergeConfig({ ortb2: ortb2 })` as documented in [the prebid.js first party data documentation](https://docs.prebid.org/features/firstPartyData.html#segments-and-taxonomy). The `targeting()` API is also called in order to retrieve and locally store the latest matching activations from `dcn.customer.com/my-site`.
433433

434434
Note that [prebid.js bidder adapters](https://docs.prebid.org/dev-docs/bidders.html) can subsequently retrieve the data from the [global config](https://docs.prebid.org/features/firstPartyData.html#supplying-global-data).
435435

@@ -503,16 +503,8 @@ For a working demo showing a `pbjs` and GAM integrated together, see the [demo p
503503
504504
pbjs.que.push(function () {
505505
optable.cmd.push(function () {
506-
const pbdata = optable.instance.prebidUserDataFromCache();
507-
if (pbdata.length > 0) {
508-
pbjs.setConfig({
509-
ortb2: {
510-
user: {
511-
data: pbdata,
512-
},
513-
},
514-
});
515-
}
506+
const ortb2 = optable.instance.prebidORTB2FromCache();
507+
pbjs.mergeConfig({ ortb2: ortb2 });
516508
517509
// ... etc ...
518510

demos/vanilla/nocookies/targeting/prebid.html.tpl

+5-13
Original file line numberDiff line numberDiff line change
@@ -153,19 +153,11 @@
153153
154154
pbjs.que.push(function () {
155155
optable.cmd.push(function () {
156-
const pbdata = optable.instance.prebidUserDataFromCache();
157-
if (pbdata.length > 0) {
158-
pbjs.setConfig({
159-
ortb2: {
160-
user: {
161-
data: pbdata
162-
}
163-
}
164-
});
156+
const ortb2 = optable.instance.prebidORTB2FromCache();
157+
pbjs.mergeConfig({ ortb2: ortb2 });
165158
166-
console.log("[OptableSDK] pbjs.setConfig(ortb2.user.data)");
167-
console.log(pbdata);
168-
}
159+
console.log("[OptableSDK] pbjs.mergeConfig(ortb2)");
160+
console.log(ortb2);
169161
170162
pbjs.setConfig({
171163
priceGranularity: "low",
@@ -240,7 +232,7 @@
240232
we also pass matching active cohorts to GAM.
241233
</p>
242234
<p>
243-
In this example, we use the <code>prebidUserDataFromCache()</code> API to retrieve any targeting data from browser
235+
In this example, we use the <code>prebidORTB2FromCache()</code> API to retrieve any targeting data from browser
244236
LocalStorage, in order to pass it to Prebid.js via <a href="https://docs.prebid.org/features/firstPartyData.html#segments-and-taxonomy">seller defined audiences</a>. We also call the SDK <code>targeting</code> API
245237
which will fetch the latest targeting data from our DCN and cache it locally for later use. Since these
246238
two events happen asynchronously, it's possible that the targeting data passed to GAM is slightly outdated.

demos/vanilla/targeting/prebid.html.tpl

+4-12
Original file line numberDiff line numberDiff line change
@@ -152,18 +152,10 @@
152152
153153
pbjs.que.push(function () {
154154
optable.cmd.push(function () {
155-
const pbdata = optable.instance.prebidUserDataFromCache();
156-
if (pbdata.length > 0) {
157-
pbjs.setConfig({
158-
ortb2: {
159-
user: {
160-
data: pbdata
161-
}
162-
}
163-
});
155+
const ortb2 = optable.instance.prebidORTB2FromCache();
156+
pbjs.mergeConfig({ ortb2: ortb2 });
164157
165-
console.log("[OptableSDK] pbjs.setConfig(ortb2.user.data)");
166-
}
158+
console.log("[OptableSDK] pbjs.mergeConfig(ortb2)");
167159
168160
pbjs.setConfig({
169161
priceGranularity: "low",
@@ -238,7 +230,7 @@
238230
we also pass matching active cohorts to GAM.
239231
</p>
240232
<p>
241-
In this example, we use the <code>prebidUserDataFromCache()</code> API to retrieve any targeting data from browser
233+
In this example, we use the <code>prebidORTB2FromCache()</code> API to retrieve any targeting data from browser
242234
LocalStorage, in order to pass it to Prebid.js via <a href="https://docs.prebid.org/features/firstPartyData.html#segments-and-taxonomy">seller defined audiences</a>. We also call the SDK <code>targeting</code> API
243235
which will fetch the latest targeting data from our DCN and cache it locally for later use. Since these
244236
two events happen asynchronously, it's possible that the targeting data passed to Prebid is slightly outdated.

lib/edge/rtb2.ts

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Based on https://github.com/InteractiveAdvertisingBureau/openrtb/blob/master/extensions/2.x_official_extensions/eids.md
2+
type UserSegment = {
3+
id?: string
4+
name?: string
5+
value?: string
6+
ext?: any
7+
};
8+
9+
type UserData = {
10+
id?: string
11+
name?: string
12+
segment?: UserSegment[]
13+
ext?: { segtax: number }
14+
};
15+
16+
type ExtendedIdentifierUID = {
17+
id: string
18+
atype: UIDAgentType;
19+
ext?: any;
20+
}
21+
22+
type ExtendedIdentifiers = {
23+
source: string;
24+
uids: ExtendedIdentifierUID[];
25+
}
26+
27+
28+
type UserExt = {
29+
eids?: ExtendedIdentifiers[];
30+
}
31+
32+
type User = {
33+
data?: UserData[]
34+
ext?: UserExt
35+
}
36+
37+
enum UIDAgentType {
38+
DeviceID = 1,
39+
InAppImpression = 2,
40+
PersonID = 3,
41+
}
42+
43+
export { User, UIDAgentType }

lib/edge/targeting.test.js

+12-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { PrebidUserData, TargetingKeyValues } from "./targeting";
1+
import { PrebidORTB2, TargetingKeyValues } from "./targeting";
22

3-
describe("PrebidUserData", () => {
3+
describe("PrebidORTB2", () => {
44
test("returns empty array on empty input", () => {
5-
expect(PrebidUserData(null)).toEqual([])
6-
expect(PrebidUserData({})).toEqual([])
5+
const empty = { user: { data: [], ext: { eids: []} }}
6+
expect(PrebidORTB2(null)).toEqual(empty)
7+
expect(PrebidORTB2({})).toEqual(empty)
78
})
89

910
test("returns for each targeting audiences a user segments compatible with ortb2.user.data", () => {
@@ -16,8 +17,13 @@ describe("PrebidUserData", () => {
1617
]
1718
};
1819

19-
expect(PrebidUserData(targeting)).toEqual(
20-
[{name: "optable.co", segment: [{ id: "a"}, {id: "b"}, {id: "c"}], ext: {segtax: 123}}]
20+
expect(PrebidORTB2(targeting)).toEqual(
21+
{
22+
user: {
23+
data: [{name: "optable.co", segment: [{ id: "a"}, {id: "b"}, {id: "c"}], ext: {segtax: 123}}],
24+
ext: { eids: [{ source: "uidapi.com", uids: [{id: "d", atype: 3}]}] },
25+
},
26+
}
2127
)
2228
})
2329
})

lib/edge/targeting.ts

+21-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { OptableConfig } from "../config";
22
import { fetch } from "../core/network";
33
import { LocalStorage } from "../core/storage";
4+
import {UIDAgentType, User as RTB2User} from "./rtb2";
45

56
type Identifier = {
67
id: string;
@@ -49,29 +50,36 @@ function TargetingClearCache(config: OptableConfig) {
4950
ls.clearTargeting();
5051
}
5152

52-
type PrebidUserSegment = Identifier
53-
type PrebidSegtax = { segtax: number };
54-
type PrebidUserSegmentProvider = { name: string; ext: PrebidSegtax; segment: PrebidUserSegment[] };
55-
type PrebidUserData = PrebidUserSegmentProvider[];
53+
type PrebidORTB2 = {user?: RTB2User}
5654

5755
/*
5856
* Prebid.js supports passing seller-defined audiences to compatible
5957
* bidder adapters.
6058
*
61-
* We return the contents to be pushed to ortb2.user.data and passed to
62-
* bidder adapters via setConfig(ortb2.user.data)... the caller is free
59+
* We return the contents to be merged in ortb2 and passed to
60+
* bidder adapters via mergeConfig(ortb2)... the caller is free
6361
* to append additional objects before setting the final result.
6462
*
6563
* References:
6664
* https://docs.prebid.org/features/firstPartyData.html#segments-and-taxonomy
6765
* https://iabtechlab.com/wp-content/uploads/2021/03/IABTechLab_Taxonomy_and_Data_Transparency_Standards_to_Support_Seller-defined_Audience_and_Context_Signaling_2021-03.pdf
6866
*/
69-
function PrebidUserData(tdata: TargetingResponse | null): PrebidUserData {
70-
return (tdata?.audience ?? []).map((identifiers) => ({
71-
name: identifiers.provider,
72-
segment: identifiers.ids,
73-
ext: { segtax: identifiers.rtb_segtax },
74-
}))
67+
function PrebidORTB2(tdata: TargetingResponse | null): PrebidORTB2 {
68+
return {
69+
user: {
70+
data: (tdata?.audience ?? []).map((identifiers) => ({
71+
name: identifiers.provider,
72+
segment: identifiers.ids,
73+
ext: { segtax: identifiers.rtb_segtax },
74+
})),
75+
ext: {
76+
eids: (tdata?.user ?? []).map((identifiers) => ({
77+
source: identifiers.provider,
78+
uids: identifiers.ids.map(({ id }) => ({ id, atype: UIDAgentType.PersonID })),
79+
})),
80+
}
81+
}
82+
}
7583
}
7684

7785
type TargetingKeyValues = { [key: string]: string[] };
@@ -99,7 +107,7 @@ export {
99107
TargetingFromCache,
100108
TargetingClearCache,
101109
TargetingResponse,
102-
PrebidUserData,
110+
PrebidORTB2,
103111
TargetingKeyValues,
104112
};
105113
export default Targeting;

lib/sdk.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import type { ProfileTraits } from "./edge/profile";
44
import { Identify } from "./edge/identify";
55
import {
66
TargetingKeyValues,
7-
PrebidUserData,
87
TargetingResponse,
98
Targeting,
109
TargetingFromCache,
11-
TargetingClearCache
10+
TargetingClearCache,
11+
PrebidORTB2
1212
} from "./edge/targeting";
1313
import { Witness } from "./edge/witness";
1414
import { Profile } from "./edge/profile";
@@ -40,13 +40,13 @@ class OptableSDK {
4040
TargetingClearCache(this.dcn);
4141
}
4242

43-
async prebidUserData(): Promise<PrebidUserData> {
44-
return PrebidUserData(await this.targeting())
43+
async prebidORTB2(): Promise<PrebidORTB2> {
44+
return PrebidORTB2(await this.targeting())
4545
}
4646

47-
prebidUserDataFromCache(): PrebidUserData {
47+
prebidORTB2FromCache(): PrebidORTB2 {
4848
const tdata = this.targetingFromCache()
49-
return PrebidUserData(tdata);
49+
return PrebidORTB2(tdata);
5050
}
5151

5252
async targetingKeyValues(): Promise<TargetingKeyValues> {
@@ -78,8 +78,8 @@ class OptableSDK {
7878
return TargetingKeyValues(tdata)
7979
}
8080

81-
static PrebidUserData(tdata: TargetingResponse): PrebidUserData {
82-
return PrebidUserData(tdata)
81+
static PrebidORTB2(tdata: TargetingResponse): PrebidORTB2 {
82+
return PrebidORTB2(tdata)
8383
}
8484
}
8585

0 commit comments

Comments
 (0)