Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prebid Core & Browsi RTD provider: Support Vendor Billing with Billable events #8119

Merged
merged 81 commits into from
Mar 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
6121b4e
real time data module,
omerDotan Aug 25, 2019
1a80b14
change timeout&primary ad server only to auctionDelay
omerDotan Sep 9, 2019
3b85815
support multiple providers
omerDotan Sep 18, 2019
0cb7b69
change promise to callbacks
omerDotan Oct 16, 2019
0908134
bug fixes
omerDotan Nov 3, 2019
cf4c5a9
use Prebid ajax
omerDotan Nov 6, 2019
7beeee3
tests fix
omerDotan Nov 6, 2019
60aaeaa
browsi real time data provider improvements
omerDotan Dec 8, 2019
0e06e6f
real time data module,
omerDotan Aug 25, 2019
e9312c7
change timeout&primary ad server only to auctionDelay
omerDotan Sep 9, 2019
c0901fe
support multiple providers
omerDotan Sep 18, 2019
398f922
change promise to callbacks
omerDotan Oct 16, 2019
b3d0bea
bug fixes
omerDotan Nov 3, 2019
a4f2de6
use Prebid ajax
omerDotan Nov 6, 2019
65ed991
tests fix
omerDotan Nov 6, 2019
15337d2
browsi real time data provider improvements
omerDotan Dec 8, 2019
76b3208
Merge remote-tracking branch 'origin/master'
omerDotan Dec 12, 2019
6a8c111
Merge remote-tracking branch 'upstream/master'
omerDotan Jan 16, 2020
b9b05f0
Merge remote-tracking branch 'upstream/master'
omerDotan Jan 20, 2020
89013d7
Merge remote-tracking branch 'upstream/master'
omerDotan Jan 21, 2020
342484c
Merge remote-tracking branch 'upstream/master'
omerDotan Jan 22, 2020
faa02bf
Merge remote-tracking branch 'upstream/master'
omerDotan Jan 28, 2020
88430b1
Merge remote-tracking branch 'upstream/master'
omerDotan Feb 11, 2020
b73b6d7
Merge remote-tracking branch 'upstream/master'
omerDotan Feb 23, 2020
00c027c
Merge remote-tracking branch 'upstream/master'
omerDotan Apr 2, 2020
51555b6
Merge remote-tracking branch 'upstream/master'
omerDotan Apr 7, 2020
c959997
Merge remote-tracking branch 'upstream/master'
omerDotan Apr 21, 2020
a277d65
Merge remote-tracking branch 'upstream/master'
omerDotan May 4, 2020
ebf1fa8
Merge remote-tracking branch 'upstream/master'
omerDotan May 25, 2020
6ec752e
Merge remote-tracking branch 'upstream/master'
omerDotan May 28, 2020
6af3494
Merge remote-tracking branch 'upstream/master'
omerDotan Jul 13, 2020
f0d9bb7
Merge remote-tracking branch 'upstream/master'
omerDotan Jul 20, 2020
608eabf
Merge remote-tracking branch 'upstream/master'
omerDotan Jul 21, 2020
6bdd935
Merge remote-tracking branch 'upstream/master'
omerDotan Jul 26, 2020
ca43a02
Merge remote-tracking branch 'upstream/master'
omerDotan Aug 10, 2020
8346da4
Merge remote-tracking branch 'upstream/master'
omerDotan Aug 23, 2020
1f5a82e
Merge remote-tracking branch 'upstream/master'
omerDotan Aug 27, 2020
1c0d024
Merge remote-tracking branch 'upstream/master'
omerDotan Sep 14, 2020
6c7cac7
Merge remote-tracking branch 'upstream/master'
omerDotan Sep 21, 2020
1543516
Merge remote-tracking branch 'upstream/master'
omerDotan Sep 23, 2020
efe5ddf
Merge remote-tracking branch 'upstream/master'
omerDotan Oct 4, 2020
b404b69
Merge remote-tracking branch 'upstream/master'
omerDotan Nov 2, 2020
107f00c
Merge remote-tracking branch 'upstream/master'
omerDotan Nov 25, 2020
cea0004
Merge remote-tracking branch 'upstream/master'
omerDotan May 18, 2021
2dcd7af
Merge remote-tracking branch 'upstream/master'
omerDotan Jun 6, 2021
86d4cf7
Merge remote-tracking branch 'upstream/master'
omerDotan Jul 5, 2021
191056f
Merge remote-tracking branch 'upstream/master'
omerDotan Jul 29, 2021
97c94b2
Merge remote-tracking branch 'upstream/master'
omerDotan Aug 8, 2021
ede3d7f
Merge remote-tracking branch 'upstream/master'
omerDotan Aug 10, 2021
e435be5
Merge remote-tracking branch 'upstream/master'
omerDotan Oct 11, 2021
6a2293e
Merge remote-tracking branch 'upstream/master'
omerDotan Oct 17, 2021
ebaba7c
initial check in
robertrmartinez Nov 10, 2021
f918fb8
Merge remote-tracking branch 'upstream/master'
omerDotan Nov 21, 2021
504eec0
first stuff
robertrmartinez Dec 1, 2021
654515b
Rubicon Passes along Billing Events
robertrmartinez Dec 17, 2021
383ae2f
fix rubi test
robertrmartinez Dec 17, 2021
d74e1fa
Merge branch 'master' of https://github.com/prebid/Prebid.js into Bil…
robertrmartinez Dec 17, 2021
9ef351c
update schema
robertrmartinez Dec 17, 2021
5b3817c
fix rubi test
robertrmartinez Dec 17, 2021
60d8c5c
Merge remote-tracking branch 'upstream/master'
omerDotan Dec 22, 2021
6f3684e
Merge branch 'master' of https://github.com/prebid/Prebid.js into Bil…
robertrmartinez Dec 22, 2021
28d6d5b
listen to billing events
robertrmartinez Jan 5, 2022
a1f37fd
Merge remote-tracking branch 'upstream/master'
omerDotan Jan 12, 2022
6dd4ea3
Merge remote-tracking branch 'upstream/master'
omerDotan Feb 1, 2022
66e782e
Merge remote-tracking branch 'upstream/master'
omerDotan Feb 3, 2022
2f16e37
Merge remote-tracking branch 'upstream/master'
omerDotan Feb 9, 2022
43c19e8
merge browsi events
robertrmartinez Feb 9, 2022
ad3855b
Merge branch 'master' of https://github.com/prebid/Prebid.js into Bil…
robertrmartinez Feb 9, 2022
1c577d8
Merge remote-tracking branch 'upstream/master'
omerDotan Feb 16, 2022
a52ac36
Merge remote-tracking branch 'upstream/master'
omerDotan Feb 20, 2022
68a705c
Merge branch 'BillingEvents' into billable-events
omerDotan Feb 20, 2022
6663f54
billable events
omerDotan Feb 20, 2022
70c9d81
remove line
omerDotan Feb 20, 2022
57ebdbf
camelcase
omerDotan Feb 20, 2022
f2b843e
Merge remote-tracking branch 'origin/billable-events' into billable-e…
omerDotan Feb 20, 2022
e45b607
lint fixes
omerDotan Feb 24, 2022
57e616b
unit test
omerDotan Feb 24, 2022
1f0ce9b
unit test
omerDotan Mar 13, 2022
3505c14
Merge remote-tracking branch 'upstream/master'
omerDotan Mar 13, 2022
8d4e683
Merge branch 'master' into billable-events
omerDotan Mar 13, 2022
a60bd1a
missing imports
omerDotan Mar 13, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions modules/browsiRtdProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@
* @property {?string} keyName
*/

import {deepClone, deepSetValue, isFn, isGptPubadsDefined, isNumber, logError} from '../src/utils.js';
import {deepClone, deepSetValue, isFn, isGptPubadsDefined, isNumber, logError, logInfo, generateUUID} from '../src/utils.js';
import {submodule} from '../src/hook.js';
import {ajaxBuilder} from '../src/ajax.js';
import {loadExternalScript} from '../src/adloader.js';
import {getStorageManager} from '../src/storageManager.js';
import {find, includes} from '../src/polyfill.js';
import {getGlobal} from '../src/prebidGlobal.js';
import events from '../src/events.js';
import CONSTANTS from '../src/constants.json';

const storage = getStorageManager();

Expand Down Expand Up @@ -106,6 +108,7 @@ export function setData(data) {
}

function getRTD(auc) {
logInfo(`Browsi RTD provider is fetching data for ${auc}`);
try {
const _bp = (_browsiData && _browsiData.p) || {};
return auc.reduce((rp, uc) => {
Expand Down Expand Up @@ -331,13 +334,23 @@ export const browsiSubmodule = {
getBidRequestData: setBidRequestsData
};

function getTargetingData(uc) {
function getTargetingData(uc, c, us, a) {
const targetingData = getRTD(uc);
const auctionId = a.auctionId
uc.forEach(auc => {
if (isNumber(_ic[auc])) {
_ic[auc] = _ic[auc] + 1;
}
const transactionId = a.adUnits.find(adUnit => adUnit.code === auc).transactionId;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that in general there may be more than one adUnit, and more than one transactionId, for a given code. Does it makes sense here to pick the first?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't ad unit code be unique?
This is how it's documented -

Unique identifier that you create and assign to this ad unit. Used to set query string targeting on the ad. If using GPT, we recommend setting this to slot element ID.
https://docs.prebid.org/dev-docs/publisher-api-reference/addAdUnits.html

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation could be improved; it also says:

https://docs.prebid.org/dev-docs/adunit-reference.html#twin-adunit-codes

It’s ok to have multiple AdUnits with the same code. This can be useful in scenarios where bidders have different capabilities for the same spot on the page.

If your aim is to emit an event for each adUnit, I'd just loop through them directly instead of the codes.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the use case for them not being unique still winds up targeting the same slot on the page.

So, perhaps the browsi use case does in fact only want to emit for each adUnitCode?

I'll let the browsi team determine that @omerBrowsi

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. adUnitCode is the right use for us

events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wouldn't this emit for every adUnit code in the auction? is requesting an auction with N ad units supposed to generate N billable events regardless of the bids it gets (or does not get)?

It'd be helpful to have a test case that shows what billable events you expect an auction to generate.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, please add actual test cases surrounding these events.

As for when the events fire, perhaps there is or needs to be some documentation on how Browsi determines it? Is it just whenever the viewability is passed into the adServer for a given adUnit?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We emit event per adUnitCode, regardless of the bids

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added unit testing

vendor: 'browsi',
type: 'adRequest',
billingId: generateUUID(),
transactionId: transactionId,
auctionId: auctionId
})
});
logInfo('Browsi RTD provider returned targeting data', targetingData, 'for', uc)
return targetingData;
}

Expand Down
4 changes: 3 additions & 1 deletion modules/rtdModule/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
* @param {string[]} adUnitsCodes
* @param {SubmoduleConfig} config
* @param {UserConsentData} userConsent
* @param {auction} auction
*/

/**
Expand Down Expand Up @@ -339,7 +340,7 @@ export function getAdUnitTargeting(auction) {
}
let targeting = [];
for (let i = relevantSubModules.length - 1; i >= 0; i--) {
const smTargeting = relevantSubModules[i].getTargetingData(adUnitCodes, relevantSubModules[i].config, _userConsent);
const smTargeting = relevantSubModules[i].getTargetingData(adUnitCodes, relevantSubModules[i].config, _userConsent, auction);
if (smTargeting && typeof smTargeting === 'object') {
targeting.push(smTargeting);
} else {
Expand All @@ -353,6 +354,7 @@ export function getAdUnitTargeting(auction) {
if (!kv) {
return
}
logInfo('RTD set ad unit targeting of', kv, 'for', adUnit);
adUnit[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING] = Object.assign(adUnit[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING] || {}, kv);
});
return auction.adUnits;
Expand Down
4 changes: 3 additions & 1 deletion src/AnalyticsAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ const {
AD_RENDER_FAILED,
AD_RENDER_SUCCEEDED,
AUCTION_DEBUG,
ADD_AD_UNITS
ADD_AD_UNITS,
BILLABLE_EVENT
}
} = CONSTANTS;

Expand Down Expand Up @@ -117,6 +118,7 @@ export default function AnalyticsAdapter({ url, analyticsType, global, handler }
[AD_RENDER_SUCCEEDED]: args => this.enqueue({ eventType: AD_RENDER_SUCCEEDED, args }),
[AUCTION_DEBUG]: args => this.enqueue({ eventType: AUCTION_DEBUG, args }),
[ADD_AD_UNITS]: args => this.enqueue({ eventType: ADD_AD_UNITS, args }),
[BILLABLE_EVENT]: args => this.enqueue({ eventType: BILLABLE_EVENT, args }),
[AUCTION_INIT]: args => {
args.config = typeof config === 'object' ? config.options || {} : {}; // enableAnaltyics configuration object
this.enqueue({ eventType: AUCTION_INIT, args });
Expand Down
3 changes: 2 additions & 1 deletion src/constants.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@
"TCF2_ENFORCEMENT": "tcf2Enforcement",
"AUCTION_DEBUG": "auctionDebug",
"BID_VIEWABLE": "bidViewable",
"STALE_RENDER": "staleRender"
"STALE_RENDER": "staleRender",
"BILLABLE_EVENT": "billableEvent"
},
"AD_RENDER_FAILED_REASON" : {
"PREVENT_WRITING_ON_MAIN_DOCUMENT": "preventWritingOnMainDocument",
Expand Down
103 changes: 100 additions & 3 deletions test/spec/modules/browsiRtdProvider_spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import * as browsiRTD from '../../../modules/browsiRtdProvider.js';
import {makeSlot} from '../integration/faker/googletag.js';
import * as utils from '../../../src/utils'
import {default as events} from '../../../src/events';
import * as sinon from 'sinon';

describe('browsi Real time data sub module', function () {
const conf = {
Expand All @@ -15,6 +17,28 @@ describe('browsi Real time data sub module', function () {
}
}]
};
const auction = {adUnits: [
{
code: 'adMock',
transactionId: 1
},
{
code: 'hasPrediction',
transactionId: 1
}
]};

let sandbox;
let eventsEmitSpy;

before(() => {
sandbox = sinon.sandbox.create();
eventsEmitSpy = sandbox.spy(events, ['emit']);
});

after(() => {
sandbox.restore();
});

it('should init and return true', function () {
browsiRTD.collectData();
Expand Down Expand Up @@ -61,13 +85,13 @@ describe('browsi Real time data sub module', function () {
describe('should return data to RTD module', function () {
it('should return empty if no ad units defined', function () {
browsiRTD.setData({});
expect(browsiRTD.browsiSubmodule.getTargetingData([])).to.eql({});
expect(browsiRTD.browsiSubmodule.getTargetingData([], null, null, auction)).to.eql({});
});

it('should return NA if no prediction for ad unit', function () {
makeSlot({code: 'adMock', divId: 'browsiAd_2'});
browsiRTD.setData({});
expect(browsiRTD.browsiSubmodule.getTargetingData(['adMock'])).to.eql({adMock: {bv: 'NA'}});
expect(browsiRTD.browsiSubmodule.getTargetingData(['adMock'], null, null, auction)).to.eql({adMock: {bv: 'NA'}});
});

it('should return prediction from server', function () {
Expand All @@ -78,7 +102,7 @@ describe('browsi Real time data sub module', function () {
pmd: undefined
};
browsiRTD.setData(data);
expect(browsiRTD.browsiSubmodule.getTargetingData(['hasPrediction'])).to.eql({hasPrediction: {bv: '0.20'}});
expect(browsiRTD.browsiSubmodule.getTargetingData(['hasPrediction'], null, null, auction)).to.eql({hasPrediction: {bv: '0.20'}});
})
})

Expand Down Expand Up @@ -135,4 +159,77 @@ describe('browsi Real time data sub module', function () {
expect(utils.deepAccess(fakeAdUnits[1], 'ortb2Imp.ext.data.browsi')).to.eql({bv: '0.10'});
})
})

describe('should emit billable event', function () {
beforeEach(() => {
eventsEmitSpy.resetHistory();
})
it('should send one event per ad unit code', function () {
const auction = {adUnits: [
{
code: 'a',
transactionId: 1
},
{
code: 'b',
transactionId: 2
},
{
code: 'a',
transactionId: 3
},
]};

browsiRTD.browsiSubmodule.getTargetingData(['a', 'b'], null, null, auction);
expect(eventsEmitSpy.callCount).to.equal(2);
})
it('should send events only for received ad unit codes', function () {
const auction = {adUnits: [
{
code: 'a',
transactionId: 1
},
{
code: 'b',
transactionId: 2
},
{
code: 'c',
transactionId: 3
},
]};

browsiRTD.browsiSubmodule.getTargetingData(['a'], null, null, auction);
expect(eventsEmitSpy.callCount).to.equal(1);
browsiRTD.browsiSubmodule.getTargetingData(['b'], null, null, auction);
expect(eventsEmitSpy.callCount).to.equal(2);
})
it('should use 1st transaction ID in case of twin ad unit codes', function () {
const auction = {
auctionId: '123',
adUnits: [
{
code: 'a',
transactionId: 1
},
{
code: 'a',
transactionId: 3
},
]};

const expectedCall = {
vendor: 'browsi',
type: 'adRequest',
transactionId: 1,
auctionId: '123'
}

browsiRTD.browsiSubmodule.getTargetingData(['a'], null, null, auction);
const callArguments = eventsEmitSpy.getCalls()[0].args[1];
// billing id is random, we can't check its value
delete callArguments['billingId'];
expect(callArguments).to.eql(expectedCall);
})
})
});
2 changes: 1 addition & 1 deletion test/spec/modules/rubiconAnalyticsSchema.json
Original file line number Diff line number Diff line change
Expand Up @@ -451,4 +451,4 @@
}
}
}
}
}