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

Rubicon project improvement/user sync #1549

Merged
merged 51 commits into from
Sep 18, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
89515a0
Add new user sync module
grevory May 15, 2017
3adaee4
Rename user sync file
grevory May 15, 2017
e233465
Reset image pixel queue after firing pixels
grevory May 17, 2017
9d20a9a
Resolved conflicts from master
grevory May 17, 2017
b7d1455
Added unit test for user sync
grevory May 23, 2017
efa23e2
Merge conflict from master
grevory May 24, 2017
9bef360
Conflict with master
grevory May 24, 2017
ca8cb54
Fixed typo
grevory May 24, 2017
b28f15b
Overlooked conflict from master
grevory May 24, 2017
7840f88
Improvements based on peer feedback for user sync
grevory May 25, 2017
7450ee5
Merge branch 'master' of https://github.com/rubicon-project/Prebid.js…
grevory Jun 6, 2017
f981c20
Added global user sync config
grevory Jun 23, 2017
66abfef
Allow auto-syncing override
grevory Jun 24, 2017
f34eb0f
Prevent syncing if there is no cookie support
grevory Jun 27, 2017
bd0cef2
Only trigger sync once per page
grevory Jul 3, 2017
4b13cc2
Limit number of user syncs per bidder
grevory Jul 10, 2017
2174667
User syncs should fire pixels without adding element to DOM
grevory Jul 11, 2017
61dbb60
Merged master into improvement/user-sync-enhancements
grevory Jul 11, 2017
c5bf2a8
Randomize user sync order by type
grevory Jul 27, 2017
94a64c7
Merge branch 'master' into improvement/user-sync-enhancements
grevory Jul 27, 2017
ff44cb7
Comment about shuffling user syncs
grevory Jul 27, 2017
26f1e20
Remove karma.conf.js and fix unused default value
grevory Jul 27, 2017
8fc8ee2
Fix prebid server adapter test to use the right cookie function
grevory Jul 27, 2017
b373c69
Added iframe support to user sync
grevory Jul 28, 2017
3f66618
Fix oversights for user sync
grevory Jul 31, 2017
c414f94
Move try catch block for user sync
grevory Aug 1, 2017
df99a16
Option to disable user sync
grevory Aug 1, 2017
a213c81
Enable specific bidders for user sync
grevory Aug 1, 2017
7cb4c24
Merge branch 'improvement/user-sync' into improvement/user-sync-enhan…
grevory Aug 1, 2017
bb30408
Merge branch 'improvement/user-sync-iframe' of https://github.com/rub…
grevory Aug 3, 2017
c1cca60
Encapsulate the user sync module
grevory Aug 3, 2017
82d1ce6
Remove unused functions for user sync
grevory Aug 6, 2017
9f6d3fd
Merge branch 'master' of https://github.com/rubicon-project/Prebid.js…
grevory Aug 6, 2017
7c71de1
Clean merge markers
grevory Aug 6, 2017
d0185d6
Merge branch 'improvement/user-sync' of https://github.com/rubicon-pr…
Aug 15, 2017
88f8197
Merge branch 'master' into improvement/user-sync
Aug 15, 2017
bd9acb4
fix usersync test problems
Aug 15, 2017
6766102
added setConfig to userSync
Aug 17, 2017
0e67a72
Merge branch 'master' into improvement/user-sync
Aug 17, 2017
2213fa5
fixed lint problem
Aug 17, 2017
e79760b
Change override user sync API and how user sync uses config
grevory Aug 29, 2017
f00a8b5
Fixed registerSync API to avoid spread operator
grevory Aug 29, 2017
f49a1e4
Merged from upstream
grevory Aug 29, 2017
9a197ab
Fixed issues from last conflict resolution
grevory Aug 30, 2017
cd5b6f5
Merge branch 'improvement/user-sync' of https://github.com/rubicon-pr…
mkendall07 Aug 31, 2017
9718d06
Small refactoring to inject dependencies better.
dbemiller Aug 31, 2017
a7a2945
Added a test for when user syncs are disabled.
dbemiller Aug 31, 2017
20ce33a
Merge branch 'master' of https://github.com/prebid/Prebid.js into rub…
dbemiller Sep 15, 2017
b555778
Implemented usersync in the base adapter.
dbemiller Sep 15, 2017
ecff1a7
user-sync updates
Sep 15, 2017
cd7206a
not tracking client bidder syncs
Sep 18, 2017
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
5 changes: 3 additions & 2 deletions modules/prebidServerBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import bidmanager from 'src/bidmanager';
import * as utils from 'src/utils';
import { ajax } from 'src/ajax';
import { STATUS, S2S } from 'src/constants';
import { queueSync, cookieSet } from 'src/cookie';
import { userSync } from 'src/userSync.js';
import { cookieSet } from 'src/cookie.js';
import adaptermanager from 'src/adaptermanager';
import { config } from 'src/config';
import { StorageManager, pbjsSyncsKey } from 'src/storagemanager';
Expand Down Expand Up @@ -144,7 +145,7 @@ function PrebidServer() {
if (result.bidder_status) {
result.bidder_status.forEach(bidder => {
if (bidder.no_cookie && !_cookiesQueued) {
queueSync({bidder: bidder.bidder, url: bidder.usersync.url, type: bidder.usersync.type});
userSync.registerSync(bidder.usersync.type, bidder.bidder, bidder.usersync.url);
}
});
}
Expand Down
39 changes: 13 additions & 26 deletions modules/rubiconBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import adaptermanager from 'src/adaptermanager';
import * as utils from 'src/utils';
import { ajax } from 'src/ajax';
import { STATUS } from 'src/constants';

import { userSync } from 'src/userSync';
const RUBICON_BIDDER_CODE = 'rubicon';

// use deferred function call since version isn't defined yet at this point
Expand Down Expand Up @@ -422,15 +422,16 @@ RubiconAdapter.masSizeOrdering = function(sizes) {
/**
* syncEmily
* @summary A user sync dependency for the Rubicon Project adapter
* When enabled, creates an user sync iframe after a delay once the first auction is complete.
* Only fires once except that with each winning creative there will be additional, similar calls to the same service.
* @example
* // Config example for Rubicon user sync
* $$PREBID_GLOBAL$$.setConfig({ rubicon: {
* userSync: {
* enabled: true,
* delay: 1000
* }
* Registers an Emily iframe user sync to be called/created later by Prebid
* Only registers once except that with each winning creative there will be additional, similar calls to the same service. Must enable iframe syncs which are off by default
@example
* // Config example for iframe user sync
* $$PREBID_GLOBAL$$.setConfig({ userSync: {
* syncEnabled: true,
* pixelEnabled: true,
* syncsPerBidder: 5,
* syncDelay: 3000,
* iframeEnabled: true
* }});
* @return {boolean} Whether or not Emily synced
*/
Expand All @@ -440,25 +441,11 @@ function syncEmily(hasSynced) {
return true;
}

const defaultUserSyncConfig = {
enabled: false,
delay: 5000
};
const iframeUrl = 'https://tap-secure.rubiconproject.com/partner/scripts/rubicon/emily.html?rtb_ext=1';

let rubiConfig = $$PREBID_GLOBAL$$.getConfig('rubicon');
let publisherUserSyncConfig = rubiConfig && rubiConfig.userSync;

// Merge publisher user sync config with the defaults
let userSyncConfig = Object.assign(defaultUserSyncConfig, publisherUserSyncConfig);

// Check that user sync is enabled
if (!userSyncConfig.enabled) {
return false;
}
// register the sync with the Prebid (to be called later)
userSync.registerSync('iframe', 'rubicon', iframeUrl);

// Delay inserting the Emily iframe
setTimeout(() => utils.insertCookieSyncIframe(iframeUrl), Number(userSyncConfig.delay));
return true;
}

Expand Down
41 changes: 25 additions & 16 deletions src/adapters/bidderFactory.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import Adapter from 'src/adapter';
import adaptermanager from 'src/adaptermanager';
import { config } from 'src/config';
import { ajax } from 'src/ajax';
import bidmanager from 'src/bidmanager';
import bidfactory from 'src/bidfactory';
import { STATUS } from 'src/constants';
import { userSync } from 'src/userSync';

import { logWarn, logError, parseQueryStringParameters, delayExecution } from 'src/utils';

Expand Down Expand Up @@ -162,9 +164,30 @@ export function newBidder(spec) {
});
}

// After all the responses have come back, fill up the "no bid" bids and
// register any required usersync pixels.
const responses = [];
function afterAllResponses() {
fillNoBids();
if (spec.getUserSyncs) {
let syncs = spec.getUserSyncs({
iframeEnabled: config.getConfig('userSync.iframeEnabled'),
pixelEnabled: config.getConfig('userSync.pixelEnabled'),
}, responses);
if (syncs) {
if (!Array.isArray(syncs)) {
syncs = [syncs];
}
syncs.forEach((sync) => {
userSync.registerSync(sync.type, spec.code, sync.url)
});
}
}
}

const bidRequests = bidderRequest.bids.filter(filterAndWarn);
if (bidRequests.length === 0) {
fillNoBids();
afterAllResponses();
return;
}
const bidRequestMap = {};
Expand All @@ -174,27 +197,13 @@ export function newBidder(spec) {

let requests = spec.buildRequests(bidRequests);
if (!requests || requests.length === 0) {
fillNoBids();
afterAllResponses();
return;
}
if (!Array.isArray(requests)) {
requests = [requests];
}

// After all the responses have come back, fill up the "no bid" bids and
// register any required usersync pixels.
const responses = [];
function afterAllResponses() {
fillNoBids();

if (spec.getUserSyncs) {
// TODO: Before merge, replace this empty object with the real config values.
// Then register them with the UserSync pool. This is waiting on the UserSync PR
// to be merged first, though.
spec.getUserSyncs({ }, responses);
}
}

// Callbacks don't compose as nicely as Promises. We should call fillNoBids() once _all_ the
// Server requests have returned and been processed. Since `ajax` accepts a single callback,
// we need to rig up a function which only executes after all the requests have been responded.
Expand Down
8 changes: 8 additions & 0 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ const DEFAULT_BIDDER_TIMEOUT = 3000;
const DEFAULT_PUBLISHER_DOMAIN = window.location.origin;
const DEFAULT_COOKIESYNC_DELAY = 100;
const DEFAULT_ENABLE_SEND_ALL_BIDS = false;
const DEFAULT_USERSYNC = {
syncEnabled: true,
pixelEnabled: true,
syncsPerBidder: 5,
syncDelay: 3000
};

const GRANULARITY_OPTIONS = {
'LOW': 'low',
Expand Down Expand Up @@ -118,6 +124,8 @@ export function newConfig() {
$$PREBID_GLOBAL$$.setS2SConfig(val);
},

// userSync defaults
userSync: DEFAULT_USERSYNC
};

function hasGranularity(val) {
Expand Down
41 changes: 0 additions & 41 deletions src/cookie.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,7 @@
import * as utils from './utils';
import adLoader from './adloader';
import { StorageManager, pbjsSyncsKey } from './storagemanager';

const cookie = exports;
const queue = [];

function fireSyncs() {
queue.forEach(obj => {
utils.logMessage(`Invoking cookie sync for bidder: ${obj.bidder}`);
if (obj.type === 'iframe') {
utils.insertCookieSyncIframe(obj.url, false);
} else {
utils.insertPixel(obj.url);
}
setBidderSynced(obj.bidder);
});
// empty queue.
queue.length = 0;
}

function setBidderSynced(bidder) {
StorageManager.add(pbjsSyncsKey, bidder, true);
}

/**
* Add this bidder to the queue for sync
* @param {String} bidder bidder code
* @param {String} url optional URL for invoking cookie sync if provided.
*/
cookie.queueSync = function ({bidder, url, type}) {
queue.push({bidder, url, type});
};

/**
* Fire cookie sync URLs previously queued
* @param {number} timeout time in ms to delay in sending
*/
cookie.syncCookies = function(timeout) {
if (timeout) {
setTimeout(fireSyncs, timeout);
} else {
fireSyncs();
}
};

cookie.cookieSet = function(cookieSetUrl) {
if (!utils.isSafariBrowser()) {
Expand Down
4 changes: 2 additions & 2 deletions src/native.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getBidRequest, logError, insertPixel } from './utils';
import { getBidRequest, logError, triggerPixel } from './utils';

export const nativeAdapters = [];

Expand Down Expand Up @@ -92,6 +92,6 @@ export function fireNativeImpressions(adObject) {
adObject.native.impressionTrackers;

(impressionTrackers || []).forEach(tracker => {
insertPixel(tracker);
triggerPixel(tracker);
});
}
17 changes: 12 additions & 5 deletions src/prebid.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { nativeAdUnit, nativeBidder, hasNonNativeBidder } from './native';
import './polyfill';
import { parse as parseURL, format as formatURL } from './url';
import { listenMessagesFromCreative } from './secureCreatives';
import { syncCookies } from './cookie';
import { userSync } from 'src/userSync.js';
import { loadScript } from './adloader';
import { setAjaxTimeout } from './ajax';
import { config } from './config';
Expand All @@ -22,6 +22,7 @@ var bidfactory = require('./bidfactory');
var events = require('./events');
var adserver = require('./adserver.js');
var targeting = require('./targeting.js');
const { syncUsers, triggerUserSyncs } = userSync;

/* private variables */

Expand Down Expand Up @@ -71,8 +72,8 @@ utils.logInfo('Prebid.js v$prebid.version$ loaded');
// create adUnit array
$$PREBID_GLOBAL$$.adUnits = $$PREBID_GLOBAL$$.adUnits || [];

/** @deprecated - use pbjs.setConfig({ cookieSyncDelay: <domain> ) */
$$PREBID_GLOBAL$$.cookieSyncDelay = $$PREBID_GLOBAL$$.cookieSyncDelay;
// Allow publishers who enable user sync override to trigger their sync
$$PREBID_GLOBAL$$.triggerUserSyncs = triggerUserSyncs;

function checkDefinedPlacement(id) {
var placementCodes = $$PREBID_GLOBAL$$._bidsRequested.map(bidSet => bidSet.bids.map(bid => bid.placementCode))
Expand Down Expand Up @@ -334,7 +335,13 @@ $$PREBID_GLOBAL$$.removeAdUnit = function (adUnitCode) {

$$PREBID_GLOBAL$$.clearAuction = function() {
auctionRunning = false;
syncCookies(config.getConfig('cookieSyncDelay'));
// Only automatically sync if the publisher has not chosen to "enableOverride"
let userSyncConfig = config.getConfig('userSync') || {};
Copy link
Collaborator

Choose a reason for hiding this comment

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

A small improvement.
Since we have default value for userSync and there is not setter for userSync. It will always return an object so no need to keep a conditional check using ||
You have also kept a test case check to validate default config.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@jaiminpanchal27 userSync can be set with config.setConfig({userSync: null}); though I'm not sure why anyone would set it to null or another falsey value, unless maybe they thought it would turn it off.

if (!userSyncConfig.enableOverride) {
// Delay the auto sync by the config delay
syncUsers(userSyncConfig.syncDelay);
}

utils.logMessage('Prebid auction cleared');
if (bidRequestQueue.length) {
bidRequestQueue.shift()();
Expand Down Expand Up @@ -695,7 +702,7 @@ $$PREBID_GLOBAL$$.buildMasterVideoTagFromAdserverTag = function (adserverTag, op
* @param {string} order One of the valid orders, described above.
* @deprecated - use pbjs.setConfig({ bidderSequence: <order> })
*/
$$PREBID_GLOBAL$$.setBidderSequence = adaptermanager.setBidderSequence
$$PREBID_GLOBAL$$.setBidderSequence = adaptermanager.setBidderSequence;

/**
* Get array of highest cpm bids for all adUnits, or highest cpm bid
Expand Down
Loading