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

Audigent Hadron: Add New Analytics Adapter #8347

Merged
merged 3 commits into from
May 12, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
199 changes: 199 additions & 0 deletions modules/hadronAnalyticsAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
import { ajax } from '../src/ajax.js';
import adapter from '../src/AnalyticsAdapter.js';
import adapterManager from '../src/adapterManager.js';
import * as utils from '../src/utils.js';
import CONSTANTS from '../src/constants.json';
import { getStorageManager } from '../src/storageManager.js';

/**
* hadronAnalyticsAdapter.js - Audigent Hadron Analytics Adapter
*/

const HADRON_ANALYTICS_URL = 'https://analytics.hadron.ad.gt/api/v1/analytics'
const HADRONID_ANALYTICS_VER = 'pbadgt0';
const DEFAULT_PARTNER_ID = 0;
const AU_GVLID = 561;

export const storage = getStorageManager();

var viewId = utils.generateUUID();

var partnerId = DEFAULT_PARTNER_ID;
var eventsToTrack = [];

var w = window;
var d = document;
var e = d.documentElement;
var g = d.getElementsByTagName('body')[0];
var x = w.innerWidth || e.clientWidth || g.clientWidth;
var y = w.innerHeight || e.clientHeight || g.clientHeight;

var pageView = {
eventType: 'pageView',
userAgent: window.navigator.userAgent,
timestamp: Date.now(),
timezoneOffset: new Date().getTimezoneOffset(),
language: window.navigator.language,
vendor: window.navigator.vendor,
pageUrl: window.top.location.href,
screenWidth: x,
screenHeight: y
};

var eventQueue = [
pageView
];

var startAuction = 0;
var bidRequestTimeout = 0;
let analyticsType = 'endpoint';

let hadronAnalyticsAdapter = Object.assign(adapter({url: HADRON_ANALYTICS_URL, analyticsType}), {
track({eventType, args}) {
args = args ? JSON.parse(JSON.stringify(args)) : {};
var data = {};
if (!eventsToTrack.includes(eventType)) return;
switch (eventType) {
case CONSTANTS.EVENTS.AUCTION_INIT: {
data = args;
startAuction = data.timestamp;
bidRequestTimeout = data.timeout;
break;
}

case CONSTANTS.EVENTS.AUCTION_END: {
data = args;
data.start = startAuction;
data.end = Date.now();
break;
}

case CONSTANTS.EVENTS.BID_ADJUSTMENT: {
data.bidders = args;
break;
}

case CONSTANTS.EVENTS.BID_TIMEOUT: {
data.bidders = args;
data.duration = bidRequestTimeout;
break;
}

case CONSTANTS.EVENTS.BID_REQUESTED: {
data = args;
break;
}

case CONSTANTS.EVENTS.BID_RESPONSE: {
data = args;
delete data.ad;
break;
}

case CONSTANTS.EVENTS.BID_WON: {
data = args;
delete data.ad;
delete data.adUrl;
break;
}

case CONSTANTS.EVENTS.BIDDER_DONE: {
data = args;
break;
}

case CONSTANTS.EVENTS.SET_TARGETING: {
data.targetings = args;
break;
}

case CONSTANTS.EVENTS.REQUEST_BIDS: {
data = args;
break;
}

case CONSTANTS.EVENTS.ADD_AD_UNITS: {
data = args;
break;
}

case CONSTANTS.EVENTS.AD_RENDER_FAILED: {
data = args;
break;
}

default:
return;
}

data.eventType = eventType;
data.timestamp = data.timestamp || Date.now();

sendEvent(data);
}
});

hadronAnalyticsAdapter.originEnableAnalytics = hadronAnalyticsAdapter.enableAnalytics;

hadronAnalyticsAdapter.enableAnalytics = function(conf = {}) {
if (typeof conf.options === 'object') {
if (conf.options.partnerId) {
partnerId = conf.options.partnerId;
} else {
partnerId = DEFAULT_PARTNER_ID;
}
if (conf.options.eventsToTrack) {
eventsToTrack = conf.options.eventsToTrack;
}
} else {
utils.logError('HADRON_ANALYTICS_NO_CONFIG_ERROR');
return;
}

hadronAnalyticsAdapter.originEnableAnalytics(conf);
}

function flush() {
// Don't send anything if no partner id was declared
if (partnerId === DEFAULT_PARTNER_ID) return;
if (eventQueue.length > 1) {
var data = {
pageViewId: viewId,
ver: HADRONID_ANALYTICS_VER,
partnerId: partnerId,
events: eventQueue
};

ajax(HADRON_ANALYTICS_URL,
() => utils.logInfo('HADRON_ANALYTICS_BATCH_SEND'),
JSON.stringify(data),
{
contentType: 'application/json',
method: 'POST'
}
);

eventQueue = [
pageView
];
}
}

function sendEvent(event) {
eventQueue.push(event);
utils.logInfo(`HADRON_ANALYTICS_EVENT ${event.eventType} `, event);

if (event.eventType === CONSTANTS.EVENTS.AUCTION_END) {
flush();
}
}

adapterManager.registerAnalyticsAdapter({
adapter: hadronAnalyticsAdapter,
code: 'hadronAnalytics',
gvlid: AU_GVLID
});

hadronAnalyticsAdapter.flush = flush;

export default hadronAnalyticsAdapter;
48 changes: 48 additions & 0 deletions modules/hadronAnalyticsAdapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Overview
Module Name: Hadron Analytics Adapter

Module Type: Analytics Adapter

Maintainer: [audigent.com](https://audigent.com)

# Hadron ID

The Hadron ID is a container that publishers and ad tech platforms can use to
recognise users' segments where 3rd party cookies are not available.
The Hadron ID is designed to respect users' privacy choices and publishers’
preferences throughout the advertising value chain.
For more information about the Hadron ID and detailed integration docs, please visit
[our brochure](https://audigent.com/hadron-id).

# Hadron Analytics Registration

The Hadron Analytics Adapter is free to use for our customers.
Please visit [audigent/hadron-id](https://audigent.com/hadron-id) to request a demo or get more info.

The partners' privacy policy is at [https://audigent.com/privacypolicy/#partners](https://audigent.com/privacypolicy/#partners).

## Hadron Analytics Configuration

First, make sure to add the Hadron Analytics submodule to your Prebid.js package with:

```
gulp build --modules=...,hadronAnalyticsAdapter
```

The following configuration parameters are available:

```javascript
pbjs.enableAnalytics({
provider: 'hadron',
options: {
partnerId: 1234, // change to the Partner ID you got from Audigent
eventsToTrack: ['auctionEnd','bidWon']
}
});
```

| Parameter | Scope | Type | Description | Example |
| --- | --- | --- |--------------------------------------------------------------------| --- |
| provider | Required | String | The name of this module: `hadronAnalytics` | `hadronAnalytics` |
| options.partnerId | Required | Number | This is the ID5 Partner Number obtained from registering with ID5. | `1234` |
Copy link
Collaborator

Choose a reason for hiding this comment

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

id5?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yikes !
thanks for catching this up

| options.eventsToTrack | Optional | Array of strings | Overrides the set of tracked events | `['auctionEnd','bidWon']` |
60 changes: 60 additions & 0 deletions test/spec/modules/hadronAnalyticsAdapter_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import adapterManager from '../../../src/adapterManager.js';
import hadronAnalyticsAdapter from '../../../modules/hadronAnalyticsAdapter.js';
import { expect } from 'chai';
import * as events from '../../../src/events.js';
import constants from '../../../src/constants.json';
import { generateUUID } from '../../../src/utils.js';
import { server } from 'test/mocks/xhr.js';

describe('Hadron analytics adapter', () => {
beforeEach(() => {
hadronAnalyticsAdapter.enableAnalytics({
options: {
partnerId: 12349,
eventsToTrack: ['auctionInit', 'auctionEnd', 'bidWon',
'bidderDone', 'requestBids', 'addAdUnits', 'setTargeting', 'adRenderFailed',
'bidResponse', 'bidTimeout', 'bidRequested', 'bidAdjustment', 'nonExistingEvent'
],
}
});
});

afterEach(() => {
hadronAnalyticsAdapter.disableAnalytics();
});

it('registers itself with the adapter manager', () => {
const adapter = adapterManager.getAnalyticsAdapter('hadronAnalytics');
expect(adapter).to.exist;
expect(adapter.gvlid).to.be.a('number');
expect(adapter.adapter).to.equal(hadronAnalyticsAdapter);
});

it('tolerates undefined or empty config', () => {
hadronAnalyticsAdapter.enableAnalytics(undefined);
hadronAnalyticsAdapter.enableAnalytics({});
});

it('sends auction end events to the backend', () => {
const auction = {
auctionId: generateUUID(),
adUnits: [{
code: 'usr1234',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600], [728, 90]]
}
},
adUnitCodes: ['usr1234']
}],
};
events.emit(constants.EVENTS.AUCTION_END, auction);
assert(server.requests.length > 0)
const body = JSON.parse(server.requests[0].requestBody);
var eventTypes = [];
body.events.forEach(e => eventTypes.push(e.eventType));
assert(eventTypes.length > 0)
assert(eventTypes.indexOf(constants.EVENTS.AUCTION_END) > -1);
hadronAnalyticsAdapter.disableAnalytics();
});
});