forked from prebid/Prebid.js
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
AirGrid RTD Submodule: Initial Release (prebid#7108)
- Loading branch information
Showing
4 changed files
with
482 additions
and
0 deletions.
There are no files selected for viewing
152 changes: 152 additions & 0 deletions
152
integrationExamples/gpt/airgridRtdProvider_example.html
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,152 @@ | ||
<html> | ||
<head> | ||
<script> | ||
var matchedAudiences = ["sport", "travel"]; | ||
window.localStorage.setItem( | ||
"edkt_matched_audience_ids", | ||
JSON.stringify(matchedAudiences) | ||
); | ||
</script> | ||
<script> | ||
var FAILSAFE_TIMEOUT = 2000; | ||
|
||
var adUnits = [ | ||
{ | ||
code: "test-div", | ||
mediaTypes: { | ||
banner: { | ||
sizes: [ | ||
[300, 250], | ||
[300, 600], | ||
[728, 90], | ||
], | ||
}, | ||
}, | ||
bids: [ | ||
{ | ||
bidder: "appnexus", | ||
params: { | ||
placementId: 13144370, | ||
}, | ||
}, | ||
], | ||
}, | ||
]; | ||
|
||
var pbjs = pbjs || {}; | ||
pbjs.que = pbjs.que || []; | ||
</script> | ||
<script src="../../build/dev/prebid.js" async></script> | ||
|
||
<script> | ||
var googletag = googletag || {}; | ||
var AUCTION_DELAY = 2000; | ||
googletag.cmd = googletag.cmd || []; | ||
googletag.cmd.push(function () { | ||
googletag.pubads().disableInitialLoad(); | ||
}); | ||
|
||
pbjs.que.push(function () { | ||
pbjs.setConfig({ | ||
debug: true, | ||
realTimeData: { | ||
auctionDelay: AUCTION_DELAY, | ||
dataProviders: [ | ||
{ | ||
name: "airgrid", | ||
waitForIt: true, | ||
params: { | ||
apiKey: "key123", | ||
accountId: "sdk", | ||
publisherId: "pub123", | ||
}, | ||
}, | ||
], | ||
}, | ||
}); | ||
pbjs.setBidderConfig({ | ||
bidders: ["appnexus", "pubmatic"], | ||
config: { | ||
ortb2: { | ||
user: { | ||
ext: { | ||
data: { | ||
registered: true, | ||
interests: ["cars"], | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}); | ||
|
||
pbjs.addAdUnits(adUnits); | ||
pbjs.requestBids({ bidsBackHandler: sendAdserverRequest }); | ||
}); | ||
|
||
function sendAdserverRequest() { | ||
document.getElementById("airgrid_audiences").innerHTML = | ||
window.localStorage.getItem("edkt_matched_audience_ids"); | ||
|
||
if (pbjs.adserverRequestSent) return; | ||
pbjs.adserverRequestSent = true; | ||
googletag.cmd.push(function () { | ||
pbjs.que.push(function () { | ||
pbjs.setTargetingForGPTAsync(); | ||
googletag.pubads().refresh(); | ||
}); | ||
}); | ||
} | ||
|
||
setTimeout(function () { | ||
sendAdserverRequest(); | ||
}, FAILSAFE_TIMEOUT); | ||
</script> | ||
|
||
<script> | ||
(function () { | ||
var gads = document.createElement("script"); | ||
gads.async = true; | ||
gads.type = "text/javascript"; | ||
var useSSL = "https:" == document.location.protocol; | ||
gads.src = | ||
(useSSL ? "https:" : "http:") + | ||
"//www.googletagservices.com/tag/js/gpt.js"; | ||
var node = document.getElementsByTagName("script")[0]; | ||
node.parentNode.insertBefore(gads, node); | ||
})(); | ||
</script> | ||
|
||
<script> | ||
googletag.cmd.push(function () { | ||
googletag | ||
.defineSlot( | ||
"/112115922/FL_PB_MedRect", | ||
[ | ||
[300, 250], | ||
[300, 600], | ||
], | ||
"test-div" | ||
) | ||
.addService(googletag.pubads()); | ||
googletag.pubads().enableSingleRequest(); | ||
googletag.enableServices(); | ||
}); | ||
</script> | ||
</head> | ||
|
||
<body> | ||
<h2>AirGrid RTD Prebid</h2> | ||
|
||
<div id="test-div"> | ||
<script> | ||
googletag.cmd.push(function () { | ||
googletag.display("test-div"); | ||
}); | ||
</script> | ||
</div> | ||
|
||
AirGrid Audiences: | ||
<div id="airgrid_audiences"></div> | ||
</body> | ||
</html> |
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,138 @@ | ||
/** | ||
* This module adds the AirGrid provider to the real time data module | ||
* The {@link module:modules/realTimeData} module is required | ||
* The module will fetch real-time audience data from AirGrid | ||
* @module modules/airgridRtdProvider | ||
* @requires module:modules/realTimeData | ||
*/ | ||
import {config} from '../src/config.js'; | ||
import {submodule} from '../src/hook.js'; | ||
import {mergeDeep, isPlainObject, deepSetValue, deepAccess} from '../src/utils.js'; | ||
import {getGlobal} from '../src/prebidGlobal.js'; | ||
import {getStorageManager} from '../src/storageManager.js'; | ||
|
||
const MODULE_NAME = 'realTimeData'; | ||
const SUBMODULE_NAME = 'airgrid'; | ||
const AG_TCF_ID = 782; | ||
export const AG_AUDIENCE_IDS_KEY = 'edkt_matched_audience_ids' | ||
|
||
export const storage = getStorageManager(AG_TCF_ID, SUBMODULE_NAME); | ||
|
||
/** | ||
* Attach script tag to DOM | ||
* @param {Object} rtdConfig | ||
* @return {void} | ||
*/ | ||
export function attachScriptTagToDOM(rtdConfig) { | ||
var edktInitializor = window.edktInitializor = window.edktInitializor || {}; | ||
if (!edktInitializor.invoked) { | ||
edktInitializor.invoked = true; | ||
edktInitializor.accountId = rtdConfig.params.accountId; | ||
edktInitializor.publisherId = rtdConfig.params.publisherId; | ||
edktInitializor.apiKey = rtdConfig.params.apiKey; | ||
edktInitializor.load = function(e) { | ||
var p = e || 'sdk'; | ||
var n = document.createElement('script'); | ||
n.type = 'text/javascript'; | ||
n.async = true; | ||
n.src = 'https://cdn.edkt.io/' + p + '/edgekit.min.js'; | ||
document.getElementsByTagName('head')[0].appendChild(n); | ||
}; | ||
edktInitializor.load(edktInitializor.accountId); | ||
} | ||
} | ||
|
||
/** | ||
* Fetch audiences from localStorage | ||
* @return {Array} | ||
*/ | ||
export function getMatchedAudiencesFromStorage() { | ||
const audiences = storage.getDataFromLocalStorage(AG_AUDIENCE_IDS_KEY); | ||
if (!audiences) return [] | ||
try { | ||
return JSON.parse(audiences); | ||
} catch (e) { | ||
return []; | ||
} | ||
} | ||
|
||
/** | ||
* Mutates the adUnits object | ||
* @param {Object} adUnits | ||
* @param {Array} audiences | ||
* @return {void} | ||
*/ | ||
function setAudiencesToAppNexusAdUnits(adUnits, audiences) { | ||
adUnits.forEach((adUnit) => { | ||
adUnit.bids.forEach((bid) => { | ||
if (bid.bidder && bid.bidder === 'appnexus') { | ||
deepSetValue(bid, 'params.keywords.perid', audiences || []); | ||
} | ||
}) | ||
}) | ||
} | ||
|
||
/** | ||
* Pass audience data to configured bidders, using ORTB2 | ||
* @param {Object} rtdConfig | ||
* @param {Array} audiences | ||
* @return {void} | ||
*/ | ||
export function setAudiencesUsingBidderOrtb2(rtdConfig, audiences) { | ||
const bidders = deepAccess(rtdConfig, 'params.bidders'); | ||
if (!bidders || bidders.length === 0) return; | ||
const allBiddersConfig = config.getBidderConfig(); | ||
const agOrtb2 = {} | ||
deepSetValue(agOrtb2, 'ortb2.user.ext.data.airgrid', audiences || []); | ||
|
||
bidders.forEach((bidder) => { | ||
let bidderConfig = {}; | ||
if (isPlainObject(allBiddersConfig[bidder])) { | ||
bidderConfig = allBiddersConfig[bidder]; | ||
} | ||
config.setBidderConfig({ | ||
bidders: [bidder], | ||
config: mergeDeep(bidderConfig, agOrtb2) | ||
}); | ||
}); | ||
} | ||
|
||
/** | ||
* Module init | ||
* @param {Object} rtdConfig | ||
* @param {Object} userConsent | ||
* @return {boolean} | ||
*/ | ||
function init(rtdConfig, userConsent) { | ||
attachScriptTagToDOM(rtdConfig); | ||
return true; | ||
} | ||
|
||
/** | ||
* Real-time data retrieval from AirGrid | ||
* @param {Object} reqBidsConfigObj | ||
* @param {function} onDone | ||
* @param {Object} rtdConfig | ||
* @param {Object} userConsent | ||
* @return {void} | ||
*/ | ||
export function passAudiencesToBidders(bidConfig, onDone, rtdConfig, userConsent) { | ||
const adUnits = bidConfig.adUnits || getGlobal().adUnits; | ||
const audiences = getMatchedAudiencesFromStorage(); | ||
if (audiences.length > 0) { | ||
setAudiencesUsingBidderOrtb2(rtdConfig, audiences); | ||
if (adUnits) { | ||
setAudiencesToAppNexusAdUnits(adUnits, audiences); | ||
} | ||
} | ||
onDone(); | ||
}; | ||
|
||
/** @type {RtdSubmodule} */ | ||
export const airgridSubmodule = { | ||
name: SUBMODULE_NAME, | ||
init: init, | ||
getBidRequestData: passAudiencesToBidders | ||
}; | ||
|
||
submodule(MODULE_NAME, airgridSubmodule); |
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,95 @@ | ||
--- | ||
layout: page_v2 | ||
title: AirGrid RTD SubModule | ||
description: Client-side, cookieless and privacy-first audiences. | ||
page_type: module | ||
module_type: rtd | ||
module_code : example | ||
enable_download : true | ||
sidebarType : 1 | ||
--- | ||
|
||
# AirGrid | ||
|
||
AirGrid is a privacy-first, cookie-less audience platform. Designed to help publishers increase inventory yield, | ||
whilst providing audience signal to buyers in the bid request, without exposing raw user level data to any party. | ||
|
||
This real-time data module provides quality first-party data, contextual data, site-level data and more that is | ||
injected into bid request objects destined for different bidders in order to optimize targeting. | ||
|
||
## Usage | ||
|
||
Compile the Halo RTD module into your Prebid build: | ||
|
||
`gulp build --modules=rtdModule,airgridRtdProvider,appnexusBidAdapter` | ||
|
||
Add the AirGrid RTD provider to your Prebid config. In this example we will configure publisher 1234 to retrieve segments from Audigent. See the "Parameter Descriptions" below for more detailed information of the configuration parameters. | ||
|
||
```js | ||
pbjs.setConfig( | ||
... | ||
realTimeData: { | ||
auctionDelay: 1000, | ||
dataProviders: [ | ||
{ | ||
name: 'airgrid', | ||
waitForIt: true, | ||
params: { | ||
// These are unique values for each account. | ||
apiKey: 'apiKey', | ||
accountId: 'accountId', | ||
publisherId: 'publisherId', | ||
bidders: ['appnexus', 'pubmatic'] | ||
} | ||
} | ||
] | ||
} | ||
... | ||
} | ||
``` | ||
### Parameter Descriptions | ||
| Name |Type | Description | Notes | | ||
| :------------ | :------------ | :------------ |:------------ | | ||
| name | `String` | RTD sub module name | Always 'airgrid' | | ||
| waitForIt | `Boolean` | Wether to delay auction for module response | Optional. Defaults to false | | ||
| params.apiKey | `Boolean` | Publisher partner specific API key | Required | | ||
| params.accountId | `String` | Publisher partner specific account ID | Required | | ||
| params.publisherId | `String` | Publisher partner specific publisher ID | Required | | ||
| params.bidders | `Array` | Bidders with which to share segment information | Optional | | ||
_Note: Although the module supports passing segment data to any bidder using the ORTB2 spec, there is no way for this to be currently monetised. Please reach out to support, to discuss using bidders other than Xandr/AppNexus._ | ||
If you do not have your own `apiKey`, `accountId` & `publisherId` please reach out to [support@airgrid.io](mailto:support@airgrid.io) | ||
## Testing | ||
To view an example of the on page setup required: | ||
```bash | ||
gulp serve-fast --modules=rtdModule,airgridRtdProvider,appnexusBidAdapter | ||
``` | ||
Then in your browser access: | ||
``` | ||
http://localhost:9999/integrationExamples/gpt/airgridRtdProvider_example.html | ||
``` | ||
Run the unit tests, just on the AirGrid RTD module test file: | ||
```bash | ||
gulp test --file "test/spec/modules/airgridRtdProvider_spec.js" | ||
``` | ||
## Support | ||
If you require further assistance or are interested in discussing the module functionality please reach out to: | ||
- [hello@airgrid.io](mailto:hello@airgrid.io) for general questions. | ||
- [support@airgrid.io](mailto:support@airgrid.io) for technical questions. | ||
You are also able to find more examples and other integration routes on the [AirGrid docs site](docs.airgrid.io). | ||
Happy Coding! 😊 | ||
The AirGrid Team. |
Oops, something went wrong.