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

Update AdButler adapter for Prebid v1.0 #1664

Merged
merged 26 commits into from
Oct 18, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
771b74c
Adding AdButler Adapter
dkharton Oct 14, 2016
45919de
Prevent AdButler TypeError
dharton Oct 19, 2016
5e72aac
Refactor AdButler Testing
dharton Oct 19, 2016
10ab721
Prevent AdButler TypeErrors
dharton Oct 24, 2016
38ad684
Merge remote-tracking branch 'refs/remotes/prebid/master'
dharton Oct 24, 2016
79e7045
Merge remote-tracking branch 'refs/remotes/prebid/master'
dharton Nov 1, 2016
7fe5aa1
Merge remote-tracking branch 'prebid/master'
dharton Nov 17, 2016
1cf22f4
Merge remote-tracking branch 'refs/remotes/prebid/master'
dharton Dec 6, 2016
eca8d59
Merge remote-tracking branch 'refs/remotes/prebid/master'
dharton Dec 14, 2016
252ffac
Merge remote-tracking branch 'refs/remotes/prebid/master'
dharton Jan 3, 2017
add7a75
Merge remote-tracking branch 'refs/remotes/prebid/master'
dharton Jan 3, 2017
35b8180
Merge remote-tracking branch 'refs/remotes/prebid/master'
dharton Jan 24, 2017
2cdc25b
Merge branch 'master' of https://github.com/sparklit/Prebid.js
dharton Jan 24, 2017
f4cac5d
Merge remote-tracking branch 'refs/remotes/prebid/master'
dharton Feb 14, 2017
c0ef919
Merge remote-tracking branch 'refs/remotes/prebid/master'
dharton Mar 6, 2017
8f85d45
Merge remote-tracking branch 'refs/remotes/prebid/master'
dharton Mar 27, 2017
1d4480a
Add optional domain parameter.
dharton Mar 27, 2017
4efc579
Merge remote-tracking branch 'refs/remotes/prebid/master'
dharton Mar 27, 2017
42b3c41
Merge remote-tracking branch 'remotes/prebid/master'
dharton Aug 17, 2017
28df88d
Merge remote-tracking branch 'remotes/prebid/master'
dharton Oct 2, 2017
5cc58bf
Merge remote-tracking branch 'remotes/prebid/master'
dharton Oct 3, 2017
cdea438
Merge remote-tracking branch 'remotes/prebid/master'
dharton Oct 6, 2017
09804e4
Update AdButler adapter to Prebid 1.0
dharton Oct 6, 2017
0117275
Code Style updates based on lint warnings.
dharton Oct 6, 2017
5af952b
Removed mutable global, simplified tests, and added markdown file.
dharton Oct 12, 2017
7ef0341
Update c1x adapter tests & remove old adbutler_spec file.
dharton Oct 17, 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
229 changes: 106 additions & 123 deletions modules/adbutlerBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,130 +1,122 @@
/**
* @overview AdButler Prebid.js adapter.
* @author dkharton
*/

'use strict';

var utils = require('src/utils.js');
var adloader = require('src/adloader.js');
var bidmanager = require('src/bidmanager.js');
var bidfactory = require('src/bidfactory.js');
var adaptermanager = require('src/adaptermanager');

var AdButlerAdapter = function AdButlerAdapter() {
function _callBids(params) {
var bids = params.bids || [];
var callbackData = {};
var zoneCount = {};
var pageID = Math.floor(Math.random() * 10e6);

// Build and send bid requests
for (var i = 0; i < bids.length; i++) {
var bid = bids[i];
var zoneID = utils.getBidIdParameter('zoneID', bid.params);
var callbackID;

if (!(zoneID in zoneCount)) {
zoneCount[zoneID] = 0;
import * as utils from 'src/utils';
import {config} from 'src/config';
import {registerBidder} from 'src/adapters/bidderFactory';

const BIDDER_CODE = 'adbutler';

export const spec = {
code: BIDDER_CODE,
pageID: Math.floor(Math.random() * 10e6),

isBidRequestValid: function (bid) {
return !!(bid.params.accountID && bid.params.zoneID);
},

buildRequests: function (validBidRequests) {
var i;
var zoneID;
var bidRequest;
var accountID;
var keyword;
var domain;
var requestURI;
var serverRequests = [];
var zoneCounters = {};

for (i = 0; i < validBidRequests.length; i++) {
bidRequest = validBidRequests[i];
zoneID = utils.getBidIdParameter('zoneID', bidRequest.params);
accountID = utils.getBidIdParameter('accountID', bidRequest.params);
keyword = utils.getBidIdParameter('keyword', bidRequest.params);
domain = utils.getBidIdParameter('domain', bidRequest.params);

if (!(zoneID in zoneCounters)) {
zoneCounters[zoneID] = 0;
}

// build callbackID to get placementCode later
callbackID = zoneID + '_' + zoneCount[zoneID];
if (typeof domain === 'undefined' || domain.length === 0) {
domain = 'servedbyadbutler.com';
}

callbackData[callbackID] = {};
callbackData[callbackID].bidId = bid.bidId;
requestURI = location.protocol + '//' + domain + '/adserve/;type=hbr;';
requestURI += 'ID=' + encodeURIComponent(accountID) + ';';
requestURI += 'setID=' + encodeURIComponent(zoneID) + ';';
requestURI += 'pid=' + encodeURIComponent(spec.pageID) + ';';
requestURI += 'place=' + encodeURIComponent(zoneCounters[zoneID]) + ';';

var adRequest = buildRequest(bid, zoneCount[zoneID], pageID);
zoneCount[zoneID]++;
// append the keyword for targeting if one was passed in
if (keyword !== '') {
requestURI += 'kw=' + encodeURIComponent(keyword) + ';';
}

adloader.loadScript(adRequest);
zoneCounters[zoneID]++;
serverRequests.push({
method: 'GET',
url: requestURI,
data: {},
bidRequest: bidRequest
});
}
return serverRequests;
},

interpretResponse: function (serverResponse, bidRequest) {
var bidObj = bidRequest.bidRequest;
var bidResponses = [];
var bidResponse = {};
var isCorrectSize = false;
var isCorrectCPM = true;
var CPM;
var minCPM;
var maxCPM;
var width;
var height;

if (serverResponse && serverResponse.status === 'SUCCESS' && bidObj) {
CPM = serverResponse.cpm;
minCPM = utils.getBidIdParameter('minCPM', bidObj.params);
maxCPM = utils.getBidIdParameter('maxCPM', bidObj.params);
width = parseInt(serverResponse.width);
height = parseInt(serverResponse.height);

// Ensure response CPM is within the given bounds
if (minCPM !== '' && CPM < parseFloat(minCPM)) {
isCorrectCPM = false;
}
if (maxCPM !== '' && CPM > parseFloat(maxCPM)) {
isCorrectCPM = false;
}

// Define callback function for bid responses
$$PREBID_GLOBAL$$.adbutlerCB = function(aBResponseObject) {
var bidResponse = {};
var callbackID = aBResponseObject.zone_id + '_' + aBResponseObject.place;
var width = parseInt(aBResponseObject.width);
var height = parseInt(aBResponseObject.height);
var isCorrectSize = false;
var isCorrectCPM = true;
var CPM;
var minCPM;
var maxCPM;
var bidObj = callbackData[callbackID] ? utils.getBidRequest(callbackData[callbackID].bidId) : null;

if (bidObj) {
if (aBResponseObject.status === 'SUCCESS') {
CPM = aBResponseObject.cpm;
minCPM = utils.getBidIdParameter('minCPM', bidObj.params);
maxCPM = utils.getBidIdParameter('maxCPM', bidObj.params);

// Ensure response CPM is within the given bounds
if (minCPM !== '' && CPM < parseFloat(minCPM)) {
isCorrectCPM = false;
}
if (maxCPM !== '' && CPM > parseFloat(maxCPM)) {
isCorrectCPM = false;
}

// Ensure that response ad matches one of the placement sizes.
utils._each(bidObj.sizes, function(size) {
if (width === size[0] && height === size[1]) {
isCorrectSize = true;
}
});

if (isCorrectCPM && isCorrectSize) {
bidResponse = bidfactory.createBid(1, bidObj);
bidResponse.bidderCode = 'adbutler';
bidResponse.cpm = CPM;
bidResponse.width = width;
bidResponse.height = height;
bidResponse.ad = aBResponseObject.ad_code;
bidResponse.ad += addTrackingPixels(aBResponseObject.tracking_pixels);
} else {
bidResponse = bidfactory.createBid(2, bidObj);
bidResponse.bidderCode = 'adbutler';
}
} else {
bidResponse = bidfactory.createBid(2, bidObj);
bidResponse.bidderCode = 'adbutler';
// Ensure that response ad matches one of the placement sizes.
utils._each(bidObj.sizes, function (size) {
if (width === size[0] && height === size[1]) {
isCorrectSize = true;
}

bidmanager.addBidResponse(bidObj.placementCode, bidResponse);
});
if (isCorrectCPM && isCorrectSize) {
bidResponse.requestId = bidObj.bidId;
bidResponse.bidderCode = spec.code;
bidResponse.creativeId = serverResponse.placement_id;
bidResponse.cpm = CPM;
bidResponse.width = width;
bidResponse.height = height;
bidResponse.ad = serverResponse.ad_code;
bidResponse.ad += spec.addTrackingPixels(serverResponse.tracking_pixels);
Copy link
Contributor

Choose a reason for hiding this comment

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

Adapters shouldn't add tracking pixels during the auction anymore. Implement getUserSyncs instead. prebid-core will make sure those pixels get added to the page alongside everyone else's

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the info @dbemiller. We offer our customers the option to track impressions on the client-side. If they've chosen this, their impression pixel would have been added here. Just to verify, if the publisher has userSync disabled, this means there is a chance their impression wouldn't be counted in this way. Is that correct?

Copy link
Contributor

Choose a reason for hiding this comment

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

Correct. Since tracking pixels affect the publisher's page performance, the prebid leadership decided that they should have the ultimate decision in whether or not to allow them.

That said, most publishers leave the default options... so it's not likely to impact you too much.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I understand the desire to improve publisher page performance. My only concern is that when all syncs are blocked, the winning bidder will not have any way to know that they have won a particular auction. Is there any way for us to provide Prebid with a URL that can be pinged or placed if our bid has won the auction?

Copy link
Member

Choose a reason for hiding this comment

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

I think there might be some confusion here. It's acceptable to add a tracking pixel to a bid response. This will only fire if the bid wins the auction. I think that's what this is so should be fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, thanks for the clarification. Yeah, this function just appends the tracking pixel(s) to the ad code in the bid response.

bidResponse.currency = 'USD';
bidResponse.netRevenue = true;
bidResponse.ttl = config.getConfig('_bidderTimeout');
bidResponse.referrer = utils.getTopWindowUrl();
bidResponses.push(bidResponse);
}
};
}

function buildRequest(bid, adIndex, pageID) {
var accountID = utils.getBidIdParameter('accountID', bid.params);
var zoneID = utils.getBidIdParameter('zoneID', bid.params);
var keyword = utils.getBidIdParameter('keyword', bid.params);
var domain = utils.getBidIdParameter('domain', bid.params);

if (typeof domain === 'undefined' || domain.length === 0) {
domain = 'servedbyadbutler.com';
}
return bidResponses;
},

var requestURI = location.protocol + '//' + domain + '/adserve/;type=hbr;';
requestURI += 'ID=' + encodeURIComponent(accountID) + ';';
requestURI += 'setID=' + encodeURIComponent(zoneID) + ';';
requestURI += 'pid=' + encodeURIComponent(pageID) + ';';
requestURI += 'place=' + encodeURIComponent(adIndex) + ';';

// append the keyword for targeting if one was passed in
if (keyword !== '') {
requestURI += 'kw=' + encodeURIComponent(keyword) + ';';
}
requestURI += 'jsonpfunc=$$PREBID_GLOBAL$$.adbutlerCB;';
requestURI += 'click=CLICK_MACRO_PLACEHOLDER';

return requestURI;
}

function addTrackingPixels(trackingPixels) {
addTrackingPixels: function (trackingPixels) {
var trackingPixelMarkup = '';
utils._each(trackingPixels, function(pixelURL) {
utils._each(trackingPixels, function (pixelURL) {
var trackingPixel = '<img height="0" width="0" border="0" style="display:none;" src="';
trackingPixel += pixelURL;
trackingPixel += '">';
Expand All @@ -133,14 +125,5 @@ var AdButlerAdapter = function AdButlerAdapter() {
});
return trackingPixelMarkup;
}

// Export the callBids function, so that prebid.js can execute this function
// when the page asks to send out bid requests.
return {
callBids: _callBids
};
};

adaptermanager.registerBidAdapter(new AdButlerAdapter(), 'adbutler');

module.exports = AdButlerAdapter;
registerBidder(spec);
31 changes: 31 additions & 0 deletions modules/adbutlerBidAdapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Overview

**Module Name**: AdButler Bidder Adapter
**Module Type**: Bidder Adapter
**Maintainer**: dan@sparklit.com

# Description

Module that connects to an AdButler zone to fetch bids.

# Test Parameters
```
var adUnits = [
{
code: 'display-div',
sizes: [[300, 250]], // a display size
bids: [
{
bidder: "adbutler",
params: {
accountID: '167283',
zoneID: '210093',
keyword: 'red', //optional
minCPM: '1.00', //optional
maxCPM: '5.00' //optional
}
}
]
}
];
```
Loading