-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Criteo real time user sync #3930
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
17bcdc8
add criteo rtus submodule and user id changes
2a96ff3
update appnexus adapter to include criteo user id
656cdbe
Merge branch 'master' of github.com:prebid/Prebid.js into criteo-rtus
58b7817
Merge branch 'master' of github.com:prebid/Prebid.js into criteo-rtus
7727b69
updated to submodules pattern
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
/** | ||
* This module adds Criteo Real Time User Sync to the User ID module | ||
* The {@link module:modules/userId} module is required | ||
* @module modules/criteortusIdSystem | ||
* @requires module:modules/userId | ||
*/ | ||
|
||
import * as utils from '../src/utils' | ||
import { ajax } from '../src/ajax'; | ||
import { submodule } from '../src/hook'; | ||
|
||
const key = '__pbjs_criteo_rtus'; | ||
|
||
/** @type {Submodule} */ | ||
export const criteortusIdSubmodule = { | ||
/** | ||
* used to link submodule with config | ||
* @type {string} | ||
*/ | ||
name: 'criteortus', | ||
/** | ||
* decode the stored id value for passing to bid requests | ||
* @function | ||
* @returns {{criteortus:Object}} | ||
*/ | ||
decode() { | ||
let uid = utils.getCookie(key); | ||
try { | ||
uid = JSON.parse(uid); | ||
return { 'criteortus': uid }; | ||
} catch (error) { | ||
utils.logError('Error in parsing criteo rtus data', error); | ||
} | ||
}, | ||
/** | ||
* performs action to obtain id and return a value in the callback's response argument | ||
* @function | ||
* @param {SubmoduleParams} [configParams] | ||
* @returns {function(callback:function)} | ||
*/ | ||
getId(configParams) { | ||
if (!configParams || !utils.isPlainObject(configParams.clientIdentifier)) { | ||
utils.logError('User ID - Criteo rtus requires client identifier to be defined'); | ||
return; | ||
} | ||
|
||
let uid = utils.getCookie(key); | ||
if (uid) { | ||
return uid; | ||
} else { | ||
let userIds = {}; | ||
return function(callback) { | ||
let bidders = Object.keys(configParams.clientIdentifier); | ||
|
||
function afterAllResponses() { | ||
// criteo rtus user id expires in 1 hour | ||
const expiresStr = (new Date(Date.now() + (60 * 60 * 1000))).toUTCString(); | ||
utils.setCookie(key, JSON.stringify(userIds), expiresStr); | ||
callback(userIds); | ||
} | ||
|
||
const onResponse = utils.delayExecution(afterAllResponses, bidders.length); | ||
|
||
bidders.forEach((bidder) => { | ||
let url = `https://gum.criteo.com/sync?c=${configParams.clientIdentifier[bidder]}&r=3`; | ||
const getSuccessHandler = (bidder) => { | ||
return function onSuccess(response) { | ||
if (response) { | ||
try { | ||
response = JSON.parse(response); | ||
userIds[bidder] = response; | ||
onResponse(); | ||
} catch (error) { | ||
utils.logError(error); | ||
} | ||
} | ||
} | ||
} | ||
|
||
const getFailureHandler = (bidder) => { | ||
return function onFailure(error) { | ||
utils.logError(`Criteo RTUS server call failed for ${bidder}`, error); | ||
onResponse(); | ||
} | ||
} | ||
|
||
ajax( | ||
url, | ||
{ | ||
success: getSuccessHandler(bidder), | ||
error: getFailureHandler(bidder) | ||
}, | ||
undefined, | ||
Object.assign({ | ||
method: 'GET', | ||
withCredentials: true | ||
}) | ||
); | ||
}) | ||
} | ||
} | ||
} | ||
}; | ||
|
||
submodule('userId', criteortusIdSubmodule); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import { criteortusIdSubmodule } from 'modules/criteortusIdSystem'; | ||
import * as utils from 'src/utils'; | ||
|
||
describe('Criteo RTUS', function() { | ||
let xhr; | ||
let requests; | ||
let getCookieStub; | ||
let logErrorStub; | ||
|
||
beforeEach(function () { | ||
xhr = sinon.useFakeXMLHttpRequest(); | ||
requests = []; | ||
xhr.onCreate = request => requests.push(request); | ||
getCookieStub = sinon.stub(utils, 'getCookie'); | ||
logErrorStub = sinon.stub(utils, 'logError'); | ||
}); | ||
|
||
afterEach(function () { | ||
xhr.restore(); | ||
getCookieStub.restore(); | ||
logErrorStub.restore(); | ||
}); | ||
|
||
it('should log error when configParams are not passed', function() { | ||
criteortusIdSubmodule.getId(); | ||
expect(logErrorStub.calledOnce).to.be.true; | ||
}) | ||
|
||
it('should call criteo endpoint to get user id', function() { | ||
getCookieStub.returns(null); | ||
let configParams = { | ||
clientIdentifier: { | ||
'sampleBidder': 1 | ||
} | ||
} | ||
|
||
let response = { 'status': 'ok', 'userid': 'sample-userid' } | ||
let callBackSpy = sinon.spy(); | ||
let submoduleCallback = criteortusIdSubmodule.getId(configParams); | ||
submoduleCallback(callBackSpy); | ||
requests[0].respond( | ||
200, | ||
{ 'Content-Type': 'text/plain' }, | ||
JSON.stringify(response) | ||
); | ||
expect(callBackSpy.calledOnce).to.be.true; | ||
expect(callBackSpy.calledWith({'sampleBidder': response})).to.be.true; | ||
}) | ||
|
||
it('should get uid from cookie and not call endpoint', function() { | ||
let response = {'appnexus': {'status': 'ok', 'userid': 'sample-userid'}} | ||
getCookieStub.returns(JSON.stringify(response)); | ||
let configParams = { | ||
clientIdentifier: { | ||
'sampleBidder': 1 | ||
} | ||
} | ||
let uid = criteortusIdSubmodule.getId(configParams); | ||
expect(requests.length).to.equal(0); | ||
}) | ||
|
||
it('should call criteo endpoint for multiple bidders', function() { | ||
getCookieStub.returns(null); | ||
let configParams = { | ||
clientIdentifier: { | ||
'sampleBidder': 1, | ||
'sampleBidder2': 2 | ||
} | ||
} | ||
|
||
let response = { 'status': 'ok', 'userid': 'sample-userid' } | ||
let callBackSpy = sinon.spy(); | ||
let submoduleCallback = criteortusIdSubmodule.getId(configParams); | ||
submoduleCallback(callBackSpy); | ||
requests[0].respond( | ||
200, | ||
{ 'Content-Type': 'text/plain' }, | ||
JSON.stringify(response) | ||
); | ||
expect(callBackSpy.calledOnce).to.be.false; | ||
requests[1].respond( | ||
200, | ||
{ 'Content-Type': 'text/plain' }, | ||
JSON.stringify(response) | ||
); | ||
expect(callBackSpy.calledOnce).to.be.true; | ||
}) | ||
}); |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this isn't going to scale out so well. Is that the only way Criteo supports (1 ID at a time?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, each bidder will have it's own client identifier. As per information we have now, this seems only option for now. There will be changes once we know more about this.