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

IntentIQ Analytics Adapter: initial release #11930

Merged
merged 30 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c85483f
IntentIQ Analytics Module
DimaIntentIQ Aug 29, 2023
ca9dc75
Merge branch 'prebid:master' into iiq_analytic_adapter
eyvazahmadzada Jun 11, 2024
a60f5ec
update intentiq analytics adapter
eyvazahmadzada Jun 11, 2024
e4f9c5a
remove percentage and change group
eyvazahmadzada Jun 11, 2024
0583ebe
update analytics adapter and tests
eyvazahmadzada Jun 11, 2024
119b244
updated flow
DimaIntentIQ Jun 4, 2024
a8947af
remove 'this'
DimaIntentIQ Jun 4, 2024
7bb6983
rename privacy parameter
DimaIntentIQ Jun 4, 2024
ce17746
add callback timeout
DimaIntentIQ Jun 4, 2024
fefca12
Extract only used parameters from CryptoJS
DimaIntentIQ Jun 4, 2024
1033bdd
add new unit tests
eyvazahmadzada Jun 4, 2024
02ec975
change callback timeout order
DimaIntentIQ Jun 5, 2024
5cb3c88
added tests and small fixes
eyvazahmadzada Jun 5, 2024
c3da09d
change saving logic
DimaIntentIQ Jun 9, 2024
9ab9f14
support "html5" and "cookie" storage types
DimaIntentIQ Jun 10, 2024
41cc517
support storage type, update flow
DimaIntentIQ Jun 10, 2024
684e7fa
add documentation
DimaIntentIQ Jun 11, 2024
2a034a9
small updates
DimaIntentIQ Jun 11, 2024
fec51df
IntentIQ Analytics Module
DimaIntentIQ Aug 29, 2023
33c36b2
Multiple modules: clean up unit tests (#11630)
dgirardi Jun 3, 2024
b204973
update intentiq analytics adapter
eyvazahmadzada Jun 11, 2024
8f46a3b
undo unnecessary changes
eyvazahmadzada Jun 11, 2024
7c13417
undo change by mistake
eyvazahmadzada Jun 11, 2024
75b04f3
Merge branch 'master' into iiq_analytic_adapter
DimaIntentIQ Jul 3, 2024
424ab9f
update params and documentation
DimaIntentIQ Jul 5, 2024
3397198
Merge pull request #1 from DimaIntentIQ/update_params
DimaIntentIQ Jul 5, 2024
3f443af
turn back storage clearing
DimaIntentIQ Jul 5, 2024
eecec04
fix linter error
DimaIntentIQ Jul 5, 2024
fc72fe7
fix wording and spelling mistakes
eyvazahmadzada Jul 8, 2024
e4d71c7
change test to handle full url to check other ids not reported
eyvazahmadzada Jul 8, 2024
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
234 changes: 234 additions & 0 deletions modules/intentIqAnalyticsAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
import { logInfo, logError } from '../src/utils.js';
import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js';
import adapterManager from '../src/adapterManager.js';
import { ajax } from '../src/ajax.js';
import { getStorageManager } from '../src/storageManager.js';
import { config } from '../src/config.js';
import { EVENTS } from '../src/constants.js';
import { MODULE_TYPE_ANALYTICS } from '../src/activities/modules.js';

const MODULE_NAME = 'iiqAnalytics'
const analyticsType = 'endpoint';
const defaultUrl = 'https://reports.intentiq.com/report';
const storage = getStorageManager({ moduleType: MODULE_TYPE_ANALYTICS, moduleName: MODULE_NAME });
const prebidVersion = '$prebid.version$';
export const REPORTER_ID = Date.now() + '_' + getRandom(0, 1000);

const FIRST_PARTY_KEY = '_iiq_fdata';
const FIRST_PARTY_DATA_KEY = '_iiq_fdata';
const JSVERSION = 0.1

const PARAMS_NAMES = {
abTestGroup: 'abGroup',
pbPauseUntil: 'pbPauseUntil',
pbMonitoringEnabled: 'pbMonitoringEnabled',
isInTestGroup: 'isInTestGroup',
enhanceRequests: 'enhanceRequests',
wasSubscribedForPrebid: 'wasSubscribedForPrebid',
hadEids: 'hadEids',
ABTestingConfigurationSource: 'ABTestingConfigurationSource',
lateConfiguration: 'lateConfiguration',
jsversion: 'jsversion',
eidsNames: 'eidsNames',
requestRtt: 'rtt',
clientType: 'clientType',
adserverDeviceType: 'AdserverDeviceType',
terminationCause: 'terminationCause',
callCount: 'callCount',
manualCallCount: 'mcc',
pubprovidedidsFailedToregister: 'ppcc',
noDataCount: 'noDataCount',
profile: 'profile',
isProfileDeterministic: 'pidDeterministic',
siteId: 'sid',
hadEidsInLocalStorage: 'idls',
auctionStartTime: 'ast',
eidsReadTime: 'eidt',
agentId: 'aid',
auctionEidsLength: 'aeidln',
wasServerCalled: 'wsrvcll',
referrer: 'vrref',
isInBrowserBlacklist: 'inbbl',
prebidVersion: 'pbjsver',
partnerId: 'partnerId'
};

let iiqAnalyticsAnalyticsAdapter = Object.assign(adapter({ defaultUrl, analyticsType }), {
initOptions: {
lsValueInitialized: false,
partner: null,
fpid: null,
currentGroup: null,
dataInLs: null,
eidl: null,
lsIdsInitialized: false,
manualReport: false
},
track({ eventType, args }) {
switch (eventType) {
case BID_WON:
bidWon(args);
break;
default:
break;
}
}
});

// Events needed
const {
BID_WON
} = EVENTS;

function readData(key) {
try {
if (storage.hasLocalStorage()) {
return storage.getDataFromLocalStorage(key);
}
if (storage.cookiesAreEnabled()) {
return storage.getCookie(key);
}
} catch (error) {
logError(error);
}
}

function initLsValues() {
if (iiqAnalyticsAnalyticsAdapter.initOptions.lsValueInitialized) return;
iiqAnalyticsAnalyticsAdapter.initOptions.fpid = JSON.parse(readData(FIRST_PARTY_KEY));
let iiqArr = config.getConfig('userSync.userIds').filter(m => m.name == 'intentIqId');
if (iiqArr && iiqArr.length > 0) iiqAnalyticsAnalyticsAdapter.initOptions.lsValueInitialized = true;
if (!iiqArr) iiqArr = [];
if (iiqArr.length == 0) {
iiqArr.push({
'params': {
'partner': -1,
'group': 'U'
}
})
}
if (iiqArr && iiqArr.length > 0) {
if (iiqArr[0].params && iiqArr[0].params.partner && !isNaN(iiqArr[0].params.partner)) {
iiqAnalyticsAnalyticsAdapter.initOptions.partner = iiqArr[0].params.partner;
iiqAnalyticsAnalyticsAdapter.initOptions.currentGroup = iiqAnalyticsAnalyticsAdapter.initOptions.fpid.group;
}
}
}

function initReadLsIds() {
if (isNaN(iiqAnalyticsAnalyticsAdapter.initOptions.partner) || iiqAnalyticsAnalyticsAdapter.initOptions.partner == -1) return;
try {
iiqAnalyticsAnalyticsAdapter.initOptions.dataInLs = null;
let iData = readData(FIRST_PARTY_DATA_KEY + '_' + iiqAnalyticsAnalyticsAdapter.initOptions.partner)
if (iData) {
iiqAnalyticsAnalyticsAdapter.initOptions.lsIdsInitialized = true;
let pData = JSON.parse(iData);
iiqAnalyticsAnalyticsAdapter.initOptions.dataInLs = pData.data;
iiqAnalyticsAnalyticsAdapter.initOptions.eidl = pData.eidl || -1;
}
} catch (e) {
logError(e)
}
}

function bidWon(args) {
if (!iiqAnalyticsAnalyticsAdapter.initOptions.lsValueInitialized) { initLsValues(); }
if (iiqAnalyticsAnalyticsAdapter.initOptions.lsValueInitialized && !iiqAnalyticsAnalyticsAdapter.initOptions.lsIdsInitialized) { initReadLsIds(); }
if (!iiqAnalyticsAnalyticsAdapter.initOptions.manualReport) {
ajax(constructFullUrl(preparePayload(args, true)), undefined, null, { method: 'GET' });
Copy link
Collaborator

Choose a reason for hiding this comment

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

just some friendly advice, your get requests are going to run out of characters and you'll eventually want to switch to post one day. the sooner you do, the less painful it will be for you

Copy link
Collaborator

Choose a reason for hiding this comment

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

also, if you pass options = keepalive, the page performance will be better and you'll be more likely to get the events after the page dies

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks a lot for the suggestion, @patmmccann! Yes, we're planning to implement these in the next updates. We would like to get the adapter approved and merged first.

}

logInfo('IIQ ANALYTICS -> BID WON')
}

function getRandom(start, end) {
return Math.floor((Math.random() * (end - start + 1)) + start);
}

export function preparePayload(data) {
let result = getDefaultDataObject();

result[PARAMS_NAMES.partnerId] = iiqAnalyticsAnalyticsAdapter.initOptions.partner;
result[PARAMS_NAMES.prebidVersion] = prebidVersion;
result[PARAMS_NAMES.referrer] = getReferrer();

result[PARAMS_NAMES.abTestGroup] = iiqAnalyticsAnalyticsAdapter.initOptions.currentGroup;

result[PARAMS_NAMES.isInTestGroup] = iiqAnalyticsAnalyticsAdapter.initOptions.currentGroup == 'A';

result[PARAMS_NAMES.agentId] = REPORTER_ID;

fillPrebidEventData(data, result);

fillEidsData(result);

return result;
}

function fillEidsData(result) {
if (iiqAnalyticsAnalyticsAdapter.initOptions.lsIdsInitialized) {
result[PARAMS_NAMES.hadEidsInLocalStorage] = iiqAnalyticsAnalyticsAdapter.initOptions.eidl && iiqAnalyticsAnalyticsAdapter.initOptions.eidl > 0;
result[PARAMS_NAMES.auctionEidsLength] = iiqAnalyticsAnalyticsAdapter.initOptions.eidl || -1;
}
}

function fillPrebidEventData(eventData, result) {
if (eventData.bidderCode) { result.bidderCode = eventData.bidderCode; }
if (eventData.cpm) { result.cpm = eventData.cpm; }
if (eventData.currency) { result.currency = eventData.currency; }
if (eventData.originalCpm) { result.originalCpm = eventData.originalCpm; }
if (eventData.originalCurrency) { result.originalCurrency = eventData.originalCurrency; }
if (eventData.status) { result.status = eventData.status; }
if (eventData.auctionId) { result.prebidAuctionId = eventData.auctionId; }

result.biddingPlatformId = 1;
result.partnerAuctionId = 'BW';
}

function getDefaultDataObject() {
return {
'inbbl': false,
'pbjsver': prebidVersion,
'partnerAuctionId': 'BW',
'reportSource': 'pbjs',
'abGroup': 'U',
'jsversion': JSVERSION,
'partnerId': -1,
'biddingPlatformId': 1,
'idls': false,
'ast': -1,
'aeidln': -1
}
}

function constructFullUrl(data) {
let report = []
data = btoa(JSON.stringify(data))
report.push(data)
return defaultUrl + '?pid=' + iiqAnalyticsAnalyticsAdapter.initOptions.partner +
'&mct=1' +
((iiqAnalyticsAnalyticsAdapter.initOptions && iiqAnalyticsAnalyticsAdapter.initOptions.fpid)
? '&iiqid=' + encodeURIComponent(iiqAnalyticsAnalyticsAdapter.initOptions.fpid.pcid) : '') +
'&agid=' + REPORTER_ID +
'&jsver=' + JSVERSION +
'&vrref=' + getReferrer() +
'&source=pbjs' +
'&payload=' + JSON.stringify(report)
}

export function getReferrer() {
return document.referrer;
}

iiqAnalyticsAnalyticsAdapter.originEnableAnalytics = iiqAnalyticsAnalyticsAdapter.enableAnalytics;

iiqAnalyticsAnalyticsAdapter.enableAnalytics = function (myConfig) {
iiqAnalyticsAnalyticsAdapter.originEnableAnalytics(myConfig); // call the base class function
};

adapterManager.registerAnalyticsAdapter({
adapter: iiqAnalyticsAnalyticsAdapter,
code: MODULE_NAME
});

export default iiqAnalyticsAnalyticsAdapter;
27 changes: 27 additions & 0 deletions modules/intentIqAnalyticsAdapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Overview

Module Name: iiqAnalytics
Module Type: Analytics Adapter
Maintainer: julian@intentiq.com

# Description

By using this Intent IQ adapter, you will be able to obtain comprehensive analytics and metrics regarding the performance of the Intent IQ Unified ID module. This includes how the module impacts your revenue, CPMs, and fill rates related to bidders and domains.
Copy link
Collaborator

@patmmccann patmmccann Jul 5, 2024

Choose a reason for hiding this comment

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

Your customers may prefer a sampling rate parameter; analytics can be a drag.


## Intent IQ Universal ID Registration

No registration for this module is required.

## Intent IQ Universal IDConfiguration

<B>IMPORTANT</B>: only effective when Intent IQ Universal ID module is installed and configured. [(How-To)](https://docs.prebid.org/dev-docs/modules/userid-submodules/intentiq.html)

No additional configuration for this module is required. We will use the configuration provided for Intent IQ Universal IQ module.

#### Example Configuration

```js
pbjs.enableAnalytics({
provider: 'iiqAnalytics'
});
```
Empty file modified modules/intentIqIdSystem.md
100755 → 100644
Empty file.
Loading