Skip to content

Appnexus adaptor - Added App parameters for hybrid apps. #2973

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

Merged
merged 5 commits into from
Aug 21, 2018
Merged
Show file tree
Hide file tree
Changes from 4 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
38 changes: 38 additions & 0 deletions modules/appnexusBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const URL = '//ib.adnxs.com/ut/v3/prebid';
const VIDEO_TARGETING = ['id', 'mimes', 'minduration', 'maxduration',
'startdelay', 'skippable', 'playback_method', 'frameworks'];
const USER_PARAMS = ['age', 'external_uid', 'segments', 'gender', 'dnt', 'language'];
const APP_DEVICE_PARAMS = ['geo', 'device_id']; // appid is collected separately
const NATIVE_MAPPING = {
body: 'description',
cta: 'ctatext',
Expand Down Expand Up @@ -59,6 +60,23 @@ export const spec = {
.forEach(param => userObj[param] = userObjBid.params.user[param]);
}

const appDeviceObjBid = find(bidRequests, hasAppDeviceInfo);
Copy link
Collaborator

Choose a reason for hiding this comment

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

@aneuway2 Just to confirm a use-case - do you foresee the chance that multiple adUnits for appnexus would ever have differing values for this device/geo fields?

This find grabs the first matching result and uses that for the value. If you had multiple adUnits with differing sets of values, only the first set of those values would be used - potentially skewing the request that gets generated.

I'm not sure this would happen, but I wanted to clarify just in case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jsnellbaker device and geo are both related to the current user, so these should remain the same between adUnits

let appDeviceObj;
if (appDeviceObjBid && appDeviceObjBid.params && appDeviceObjBid.params.app) {
appDeviceObj = {};
Object.keys(appDeviceObjBid.params.app)
Copy link
Collaborator

Choose a reason for hiding this comment

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

This will throw error if params is undefined. Please add a check on line 66 to check that it exists.

.filter(param => includes(APP_DEVICE_PARAMS, param))
.forEach(param => appDeviceObj[param] = appDeviceObjBid.params.app[param]);
}

const appIdObjBid = find(bidRequests, hasAppId);
let appIdObj;
if (appIdObjBid && appIdObjBid.params && appDeviceObjBid.params.app && appDeviceObjBid.params.app.id) {
appIdObj = {
appid: appIdObjBid.params.app.id
Copy link
Collaborator

Choose a reason for hiding this comment

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

This will throw error if params and app are undefined. To access nested property you need to add check that it exist.

};
}

const memberIdBid = find(bidRequests, hasMemberId);
const member = memberIdBid ? parseInt(memberIdBid.params.member, 10) : 0;

Expand All @@ -74,6 +92,13 @@ export const spec = {
payload.member_id = member;
}

if (appDeviceObjBid) {
payload.device = appDeviceObj
}
if (appIdObjBid) {
payload.app = appIdObj;
}

if (bidderRequest && bidderRequest.gdprConsent) {
// note - objects for impbus use underscore instead of camelCase
payload.gdpr_consent = {
Expand Down Expand Up @@ -381,6 +406,19 @@ function hasMemberId(bid) {
return !!parseInt(bid.params.member, 10);
}

function hasAppDeviceInfo(bid) {
if (!!bid.params) {
return !!bid.params.app
}
}

function hasAppId(bid) {
if (!!bid.params.app) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Add check for nested access

return !!bid.params.app.id
}
return !!bid.params.app
}

function getRtbBid(tag) {
return tag && tag.ads && tag.ads.length && find(tag.ads, ad => ad.rtb);
}
Expand Down
41 changes: 38 additions & 3 deletions modules/appnexusBidAdapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@ Appnexus bid adapter supports Banner, Video (instream and outstream) and Native.
var adUnits = [
// Banner adUnit
{
code: 'banner-div',
sizes: [[300, 250], [300,600]],
bids: [{
code: 'banner-div',
mediaTypes: {
banner: {
sizes: [[300, 250], [300,600]]
}
}
bids: [{
bidder: 'appnexus',
params: {
placementId: '10433394'
Expand Down Expand Up @@ -98,6 +102,37 @@ var adUnits = [
}
}
]
},
// Banner adUnit in a App Webview
// Only use this for situations where prebid.js is in a webview of an App
// See Prebid Mobile for displaying ads via an SDK
{
code: 'banner-div',
mediaTypes: {
banner: {
sizes: [[300, 250], [300,600]]
}
}
bids: [{
bidder: 'appnexus',
params: {
placementId: '10433394',
app: {
id: "B1O2W3M4AN.com.prebid.webview",
geo: {
lat: 40.0964439,
lng: -75.3009142
},
device_id: {
idfa: "4D12078D-3246-4DA4-AD5E-7610481E7AE", // Apple advertising identifier
aaid: "38400000-8cf0-11bd-b23e-10b96e40000d", // Android advertising identifier
md5udid: "5756ae9022b2ea1e47d84fead75220c8", // MD5 hash of the ANDROID_ID
sha1udid: "4DFAA92388699AC6539885AEF1719293879985BF", // SHA1 hash of the ANDROID_ID
windowsadid: "750c6be243f1c4b5c9912b95a5742fc5" // Windows advertising identifier
}
}
}
}]
}
];
```
44 changes: 44 additions & 0 deletions test/spec/modules/appnexusBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,50 @@ describe('AppNexusAdapter', () => {
expect(payload.gdpr_consent.consent_string).to.exist.and.to.equal(consentString);
expect(payload.gdpr_consent.consent_required).to.exist.and.to.be.true;
});

it('supports sending hybrid mobile app parameters', () => {
let appRequest = Object.assign({},
bidRequests[0],
{
params: {
placementId: '10433394',
app: {
id: "B1O2W3M4AN.com.prebid.webview",
geo: {
lat: 40.0964439,
lng: -75.3009142
},
device_id: {
idfa: "4D12078D-3246-4DA4-AD5E-7610481E7AE", // Apple advertising identifier
aaid: "38400000-8cf0-11bd-b23e-10b96e40000d", // Android advertising identifier
md5udid: "5756ae9022b2ea1e47d84fead75220c8", // MD5 hash of the ANDROID_ID
sha1udid: "4DFAA92388699AC6539885AEF1719293879985BF", // SHA1 hash of the ANDROID_ID
windowsadid: "750c6be243f1c4b5c9912b95a5742fc5" // Windows advertising identifier
}
}
}
}
);
const request = spec.buildRequests([appRequest]);
const payload = JSON.parse(request.data);
expect(payload.app).to.exist;
expect(payload.app).to.deep.equal({
appid: "B1O2W3M4AN.com.prebid.webview"
});
expect(payload.device.device_id).to.exist;
expect(payload.device.device_id).to.deep.equal({
aaid: "38400000-8cf0-11bd-b23e-10b96e40000d",
idfa: "4D12078D-3246-4DA4-AD5E-7610481E7AE",
md5udid: "5756ae9022b2ea1e47d84fead75220c8",
sha1udid: "4DFAA92388699AC6539885AEF1719293879985BF",
windowsadid: "750c6be243f1c4b5c9912b95a5742fc5"
});
expect(payload.device.geo).to.exist;
expect(payload.device.geo).to.deep.equal({
lat: 40.0964439,
lng: -75.3009142
});
});
})

describe('interpretResponse', () => {
Expand Down