Welcome to the Index Exchange Partner Certification Process!
Below you will find everything you need to complete the certification process and be a part of the Header Tag Wrapper! Should you have any questions, please refer to this README first, it should cover everything you need to complete the certification.
Good Luck!
README.md
-This is the main documentation file which should contain everything you need to complete the certification process. If anything is unclear, please refer to this document first.partnerConfig.js
- This is the configuration object that contains your partner specific configs.headerTagWrapper.js
- A minified version of our Header Tag Wrapper.index.html
- A simple test page that contains some googletag slots and loads our wrapper for testing purposes.partner-adapter
- Folder that contains the partner module (most of the development should be done in this folder)partnerModule.js
- This is your partner module file, by default it contains a template divided into multiple sections which need to be completed.package.json
- This is a file containing metadata used by the Index Exchange development team.
-
Git Setup
- Clone the repository, checkout the certification branch, and checkout appropriate submodule branch.
# clone the repo git clone https://github.com/indexexchange/ht-wrapper-certification.git # checkout the certification branch cd ht-wrapper-certification git checkout partner-certification # register and update the bidder adapter git submodule init git submodule update --remote
# checkout the development branch for the partner adapter submodule cd partner-adapter git checkout development
-
Host the repo locally
- Once the repo is hosted locally, you should be able to see a simple test page with 4 googletag slots defined (3 desktop and 1 mobile).
- By default, the Index Exchange adapter will be bidding $1.50 on all slots except the 728x90 leaderboard slot.
- By default, you should see Index Exchange certification ads rendering on all slots except that 728x90 leaderboard slot, which should be rendering a default/house ad.
- Once you have setup your module, you can test the auction by bidding higher or lower to see your ads winning.
-
Complete the
partnerModule.js
file in the partner-adapter folder.- partnerModule.js is where all of your adapter code will live.
- In order to complete the partner module correctly, please refer to the Partner Module Overview and the Utility Libraries sections.
- Please refer to the Partner Requirements and Guidelines when creating your module. Ensure requirements are met to streamline the review process.
- The module is automatically loaded by the test page, so once your code has been added, you will be able to test it right away.
-
Complete the partnerConfig.js
- This file is where your partner-specific configuration and slot mappings will be defined.
- Please complete your module's configuration with appropriate xSlot data and mappings. For more information on xSlots, refer to the Configuration section of this README.
-
Committing changes to GitHub
- Please make sure that you're in the correct directory
# commit all the changes in the ht-wrapper-certification directory git commit -am "commit message" git push origin partner-certification
# commit all the changes in the partner-adapter directory git commit -am "commit message" git push origin development
-
Testing and Verification
- Once your partner module has been completed and your partner-specific configuration has been added to partnerConfig.js, you are ready to start testing.
- Open the index.html test page and you should see the HeaderTagWrapper loaded as well as your partnerModule.
- In order to confirm your module's functionality, please complete the required test plan outlined below in this readme.
-
Submitting for Review
- Once the module has been verified, go to the GitHub page of the partner adapter.
- Submit a pull request from the
development
branch to themaster
branch for the Index Exchange team to review. If everything is approved, your adapter will be officially certified! - You may push any changes to the partnerConfig.js directly to the certification branch.
Our standard creative tag in dfp looks as follows:
<script type="text/javascript">
var w = window;
for (var i = 0; i < 10; i++) {
w = w.parent;
if (w.headertag) {
try {
w.headertag.PRTN.render(document, %%PATTERN:TARGETINGMAP%%, '%%WIDTH%%', '%%HEIGHT%%');
break;
} catch (e) {
continue;
}
}
}
</script>
In order for your module to be successfully certified, please refer to the following list of requirements and guidelines. Items under required must be satisfied in order to pass the certification process. Items under guidelines are recommended for an optimal setup and should be followed if possible.
- The only targeting keys that can be set are predetermined by Index. The partner module should not be setting targeting on other keys.
- Must support the following browsers: IE 9+, Edge, Chrome, Safari, and Firefox
- Please use our helper libraries when possible. Refer to our utilities library documentation below. All of the utility functions in this library are designed to be backwards compatible with supported browsers to ease cross-browser compatibility.
- Must provide cache busting parameter. Cache busting is required to prevent network caches.
- Partner endpoint domain must be consistent and cannot be configurable. Load balancing should be performed by the endpoint.
- Your module should support a single request architecture (SRA) which has a capability to send multiple bid requests in a single HTTP request.
- Your endpoint should support HTTPS request. When wrapper loads in secure pages, all requests need to be HTTPS. If you're unable to provide a secure endpoint, we will not be able to make requests to your ad servers.
- Partner should use AJAX method to make bid requests. Please use our Network utility library for making network requests, particularly the
Network.ajax
method. This ensures the requests will work with all browsers.
- Returned bid must be a net bid.
- Pass on bid must be explicit in the response. When you pass on a bid, it must be explicit such that the wrapper does not need to wait until auction times out.
- All returned bids shall be in the currency trafficked by the publisher.
- Size must be returned in the response. The sizes must also match the requested size. This size parameter will be validated.
- Encrypted prices must be flagged in the response.
- Pixels/beacons must only be dropped only when the partner wins the auction and their ad renders.
- Dropping pixels during auction slows down the execution of auctions and is not allowed by Index Exchange.
- DFP line items, creatives, and render functions will be set up by the Index Exchange team.
The main configuration object that is used by the Header Tag Wrapper is the headertagconfig
object. This configuration is configured by the publisher.
This object contains all the configuration required for the wrapper, including partner specific slot mappings, timeouts, and any other partner specific configuration.
The partner specific slot mappings dictate how ad slots on the page will map to partner specific configuration.
There are 2 concepts to be familiar with when understanding how slots on the page are mapped back to partner specific configuration. Header Tag Slots, which refers to htSlots and partner-specific configuration, which refers to xSlots in the codebase.
- htSlots - This is an abstraction of the googletag.Slot object.
- htSlot id's will be passed into the partner's
getDemand
functions. - These will need to be mapped to xSlots.
- htSlot id's will be passed into the partner's
- xSlots - These are also an abstraction for partner specific configuration that will be mapped to htSlots.
- These represent a single partner specific configuration.
- An xSlot is how a partner can map their ad server specific identifiers (placementIDs, siteIDs, zoneIDs, etc) to the
googletag.Slot
object represented as anhtSlot
. - It can represent a single or multiple sizes.
- Multiple xSlots can be mapped to the same htSlot.
- An xSlot can only be mapped to a single htSlot.
Example Partner Configuration Mapping
{
"partners": {
"PRTN": {
"xSlots": {
"xSlot1": {
"placementID": "123",
"sizes": [ [300, 250], [300, 600] ]
},
"xSlot2": {
"placementID": "345",
"sizes": [ [300, 250] ]
}
},
"mapping": {
"htSlotID-1": [ "xSlot1" ],
"htSlotID-2": [ "xSlot2" ]
}
}
}
}
The partner module would need to map the htSlotIDs to xSlots when demand is requested.
- The Header Tag Wrapper script tag is loaded on the page.
- Wrapper specific configuration validation is performed.
- All the partner modules are instantiated.
- Partner specific configuration validation is performed - checking that all the required fields are provided and that they are in the correct format.
- A googletag display or refresh call is made.
The wrapper requests demand from the partner modules for the required slots (the slots being refreshed or displayed).
- The wrapper calls
getDemand
for every partner module. - The partner module again maps the required
htSlots
to the respective xSlots. - If not, demand is fetched by the partner module and stored in in a demand object.
- Once all demand for all required slots have been retrieved by the partner, the demand is returned to the wrapper.
- The wrapper calls
- The wrapper applies targeting using the keys specified by the partner.
- If the partner wins the auction in gdfp, their creative code will be returned and executed.
- The creative code contains a call to a partner module render function.
- The partner ad is rendered.
The parter module needs to initialize itself. This includes validating the configuration its been provided with.
This section is mainly about setting up the behavior of partner itself. Things like targeting types, partnerID (used internally to reference the partner), and different types of analytics are supported.
This section is for validating partner specific configuration that is provided by the user. Slot mappings and other fields that are required for all adapters are validated for you. If there are partner specific fields that need validation, this is the place to validate them.
Similar to section B but for any partner specific xSlot mapping information (i.e. placementID must be a number).
This section is for simply copying any useful information (such as slot mappings) from the main configuration object to internal variables. Creating a direct map from htSlotID to an xSlot and vice versa would be useful to have and can be done here.
In this section, the partner module needs to request demand for the htSlots that are provided in the info variable. The info variable contains the htSlotIds for which demand needs to be gathered. These htSlotIDs
need to be first mapped back to partner specific xSlots.
The partner module should then make a demand request to their server. Once the request is complete, the returned demand should be processed, and stored under the htSlotID that it was initially requested for in the demandStore[correlator]
object for later consumption.
Any returned creative code must be stored inside the global creativeStore
object.
This step is for retrieving demand when a googletag display or a refresh call is made.
In this section the partner must fetch demand for the requested htSlots that was provided in the slots object. These slots must be mapped back to xSlots and the appropriate xSlots must be fetched. Once all slots have been fetched and parsed, they must be mapped back to htSlotIDs and be placed in a demand object. In this format:
{
slot: {
<htSlotId>: { // the htslotID
timestamp: Utils.now(),
demand: {
<key>: <value>, // key is the targeting key, should be targeting
<key>: <value>,
...
}
},
...
}
}
Any returned creative code must be stored inside the global creativeStore
object using some sort of unique id and size.
The targeting keys should be the keys found in the targetingKeys
object. This should include the ix_prtn_cpm
for open/private market bids by price and ix_prtn_dealid
for private market bids by deal id. The targeting key correlates the request with the creative retrieve from the creativeStore
object in the renderAd
function if the partner is to win the auction. Which is then passed to the renderAd
function on a win, and used to retrieve the creative.
Once all the demand has been gathered, the partner module should invoke the provided callback with the demand as an argument.
This section is an optional response callback that can be used for parsing any demand that is returned.
This step is for rendering the winning creative. If the partner module's line item wins, the creative code will be returned and inserted into the iframe for that googletag slot. The standard creative code will contain a call to the partner module's specific renderAd
function.
The function in Section J should work as is as long as the creative is stored correctly in the getDemand
function.
There are three helper objects available to you in you partner module.
- Utils - contains numerous utility and validation helper methods.
- Network - contains helper methods for making network request.
- BidRoundingTransformer - contains helper methods for rounding and transforming bids.
isObject(entity)
- Return true if entity is an object.isArray(obj)
- Return true if obj is an array.isNumber(entity)
- Return true if entity is a number.isString(entity)
- Return true if entity is a string.isBoolean(entity)
- Return true if entity is a boolean.isFunction(entity)
- Return true if entity is a function.isEmpty(entity)
- if entity is a string, return true if string is empty.
- if entity is an object, return true if the object has no properties.
- if entity is an array, return true if the array is empty.
isInRange(value, min, max)
- return true ifmax > value > min
.isArraySubset(arr1, arr2, matcher)
- Return true ifarr1
is a subset ofarr2
.
getGSlots()
- Return an array of google tag slots on the page.divIdToGSlot(divId)
- Return the googletag slot associated withdivId
.getGSlotDivIds(slots)
- Return the divIDs of the google tag slotsslots
.
now()
- Return the number of milliseconds since 1970/01/01.
getDeviceTypeByUserAgent()
- Return 'mobile' or 'desktop' based on userAgentgetViewportWidth()
- Return viewport width.getViewportHeight()
- Return viewport height.getProtocol(httpValue, httpsValue)
- Returndocument.location.protocol
orhttpValue
ifdocument.location.protocol
is http andhttpsValue
ifdocument.location.protocol
is https.getPageUrl()
- Return the page's url.addScriptTag(src, asyncEnabled, onLoad)
- Appends a script tag onto the page withsrc
, usingasyncEnabled
to toggle async andonLoad
callback when the script finishes loading.
generateCorrelator()
- Generates a random correlator value, used internally inside the header tag wrapper to identify different sessions.randomSplice(arr)
- Randomly splice an arrayarr
.
objToQueryString(obj)
- Creates a query string based on the properties of the objectobj
.isXhrSupported()
- Return true is Xhr requests are supported in the current browser/page.buildUrl(base, path, queryString)
- Return a url string using the givenbase
url,path
, andqueryString
object.ajax(args)
- This should be the default method for making all of your bid requests. Make an ajax network request using theargs
object, which should be of the form:url
- url stringmethod
- the method of the request (i.e. GET).partnerId
- the id of the partner, used for stats.jsonp
- flag to signifify a jsonp request.withCredentials
- withCredentials flag.onSuccess
- on success callback.onFailure
- on failure callback.
jsonp(args)
- Same as ajax but only for jsonp requests, use this if the above does not work.
transformBid(rawBid)
- Transform rawBid into the configured format. This includes, rounding/flooring according to the bidTransformConfig that was used to instantiate the library. The bidTransformConfig is an object of the format:floor
- Minimum acceptable bid price.inputCentsMultiplier
- Multiply input bids by this to get cents.outputCentsDivisor
- Divide output bids in cents by this.outputPrecision
- Decimal places in output.roundingType
- Should always be 1.buckets
- Buckets specifying rounding steps.
Example of bidTransformConfig
:
var __bidTransformConfig = { // Default rounding configuration
'floor': 0,
'inputCentsMultiplier': 100, // Input is in dollars
'outputCentsDivisor': 1, // Output as Cents
'outputPrecision': 0, // With 0 decimal places
'roundingType': 1, // Floor instead of round
'buckets': [{
'max': 2000, // Up to 20 dollar (above 5 cents)
'step': 5 // use 5 cent increments
}, {
'max': 5000, // Up to 50 dollars (above 20 dollars)
'step': 100 // use 1 dollar increments
}]
};
Before submitting your module for review by Index Exchange, your module must satisfy the below test cases.
- The partner module is sending bid requests.
- Sending requests for the correct slots, placements, sizes, etc.
- The bids are hitting the correct url with the correct query parameters.
- The partner module is correctly parsing the returned bid responses.
- The bid responses are being parsed correctly.
- The bids are being stored correctly in
demand
(for regular demand). - The creatives are being stored correctly in the
creativeStore
object.
- Targeting is correctly applied and present on google tags
ads?
requests.- The partner specific key,
ix_prtn_cpm
for open/private market bids by price andix_prtn_dealid
for private market bids by deal id should be present. - The current values for those keys should be set.
- The partner specific key,
- Partner-Specific test ads are displaying.
- In order to see your test ads displaying, you must win the auction in DFP.
- We have 2 sets of test line items setup for the open/private market bids by price and 1 set of test line items setup for the private market bids by deal id for your specific targeting key.
- One for $1.00 bids, one for $2.00 bids, and one for a deal with deal id
deal
. This is so you can see win/loss against our default index bids of $1.50.
- One for $1.00 bids, one for $2.00 bids, and one for a deal with deal id
- Hence to see your ads displaying, you must return $2.00 bids or private market deals with dealId=
deal
that gets passed into dfp through your targeting key.- For bid by price example,
ix_prtn_cpm=300x250_200
- For bid by deal id example,
ix_prtn_dealid=300x250_deal
- For bid by price example,
- We have 2 sets of test line items setup for the open/private market bids by price and 1 set of test line items setup for the private market bids by deal id for your specific targeting key.
- Your returned creatives should be activating line items and winning with the correct bids.
- In order to see your test ads displaying, you must win the auction in DFP.