KARMA is Meredith's in-house Javascript framework for serving up ads on websites. It's essentially a wrapper around Google's Publisher Tags (GPT). KARMA gathers information about the page, the user, and the ad slots desired, then requests those ads from GAM (Google Ad Manager, Google's ad serving platform).
KARMA is different from stock GPT in that it seamlessly integrates with many of Meredith's third-party revenue partners, requesting real-time bids for programmatic and intent-based premium ad content. KARMA also gives you access to the full suite of Meredith's ad playbook products, with minimal technical integration. We also handle things like timed refresh, dynamic injection of ads, and leaderboard/right rail docking.
To integrate KARMA on your website, you need two basic pieces:
PLEASE NOTE: You can only use the KARMA 3 integration OR the KARMA 2 integration. A horrible Frankenstein's-monster amalgamation of both WILL NOT WORK. Please see the KARMA 3 Migration Guide for more details.
<html>
<head>
<!-- KARMA config/init snippet goes here -->
</head>
<body>
<!-- KARMA placeholder DIV tags go here -->
</body>
</html>
A chunk of inline Javascript in the head of your site, which tells us what kind of page and device we're on, does ad-block detection, then makes the call to initialize KARMA.
You will need to modify this code to reflect values for your site. More details on each property are below in the KARMA config properties section.
<head> config/init snippet<script>
window.karma = window.karma || {};
window.karma.config = {
apiVersion: 3, /* REQUIRED: which version of the KARMA API are we using? */
isMobile: false, /* REQUIRED: are we on a mobile device or not? */
site: 'bhg.mdp.com', /* OPTIONAL, only if your domain is weird and KARMA can't auto-detect the site */
targeting: {
id: '12394875', /* REQUIRED: a page-specific unique identifier, alphanumeric, <=40 characters */
type: 'article', /* REQUIRED: what type of page is this? */
channel: 'gardening', /* REQUIRED: a top level category identifier */
kw: ['chicken', 'frog', 'marshmallow'], /* keywords: if multiple values are passed, it must be an array of strings */
search: '', /* On search results, set to the search term */
foo: 'bar', /* you can add any other key/value pairs here */
},
};
window.karma.config.callback = window.karma.config.callback || [];
window.karma.config.callback.push(function(){ /* a function that runs every time an ad renders */ });
!function(e,a){function r(){if(null===a.querySelector('img[src$="kismet/spacer.png"]')){var e=a.createElement("img");e.src="/kismet/spacer.png",a.body.appendChild(e)}}e.karma.cmd=e.karma.cmd||[],e.karma.config.go=function(){e.karma.cmd.push("go")};var n=a.createElement("script");n.src="https://karma.mdpcdn.com/service/js-min/karma.js",n.onload=n.onreadystatechange=function(){var e=this.readyState;e&&"complete"!=e&&"loaded"!=e&&r()},n.onerror=r;var t=a.getElementsByTagName("script")[0];t.parentNode.insertBefore(n,t)}(window,document);
</script>
Empty div tags in the HTML that tell us where and what kind of ads should display. These divs have unique ids and data attributes that tell us the ad slot size and position.
Not sure which placeholder you need? Check out our list of placeholders here.
<body> placeholders:<!-- this tells KARMA to request a flexible leaderboard slot (728x90, 970x66, etc) with excellent visibility -->
<div id="div-gpt-leaderboard-flex-1" data-tier="1" role="complementary" aria-hidden="true"></div>
<!-- this tells KARMA to request a mobile fixed square slot (300x250) with excellent visibility -->
<div id="div-gpt-mob-square-fixed-1" data-tier="1" role="complementary" aria-hidden="true"></div>
Instant slots are any slots that load immediately upon KARMA initialization. By default KARMA placehodler divs will load instant slots.
Lazy scroll slots are included in the HTML markup, but they are not requested until the user scrolls within a specified pixel threshold (karma.config.lazyScrollThreshold). Slots are treated as lazy scroll if they have the data-lazy-scroll="true" attribute. Lazy scroll slots are requested in batches as set by karma.config.lazyScrollBatchSize. Lazy scroll slots are treated like instant slots if they are within the threshold at the time of the ad request.
<div id="div-gpt-square-fixed-1" data-tier="1" data-lazy-scroll="true" role="complementary" aria-hidden="true"></div>
By default, KARMA will listen for the DOMContentLoaded event to trigger the scraping of the DOM for ad slots to fill. Alternatively, for finer tuning, a call to window.karma.config.go() can be placed on the page as an inline script to inform KARMA that all ad slots are on the page and the DOM is ready to be scraped.
For pages that modify or build the DOM dynamically, the property karma.config.bypassDOMReady can be set to true. This bypasses the DOMContentLoaded listener and relies soley on the page to call karma.config.go() to initialize the ad slots.
Note: window.karma.config.go is defined in the minified KARMA initial load snippet, so your call to window.karma.config.go() must be included after that definition.
karma.config.go():<!-- If used, the call to go() should be placed after the last slot on the page. This tells KARMA that all slots are on the page and the DOM is ready to be processed. -->
<div id="div-gpt-square-fixed-3" data-tier="4" role="complementary" aria-hidden="true"></div>
<script>
karma.config.go();
</script>
For a fully functioning example of a page that has nothing but KARMA ads on it, see:
Specific documentation on the on-page KARMA configuration properties follows.
KARMA also sets configuration properties on our end. See inspecting KARMA Config values for more.
<head> config/init snippetwindow.karma.config = {
apiVersion: 3, /* REQUIRED */
isMobile: false, /* REQUIRED */
site: 'bhg.mdp.com', /* only needed if your domain is weird */
targeting: {
id: '12394875', /* REQUIRED */
type: 'article', /* REQUIRED */
channel: 'gardening', /* REQUIRED */
kw: ['chicken', 'frog', 'marshmallow'],
search: '',
foo: 'bar',
},
};
window.karma.config.callback = window.karma.config.callback || [];
window.karma.config.callback.push(function(){ /* a function that runs every time an ad renders */ });
Type: number
Currently, we have some sites using a legacy (v2.x) KARMA integration with a different configuration pattern. While we're transitioning sites over to KARMA 3.x, we require the apiVersion parameter to let us know that we're on a KARMA 3.x site.
window.karma.config = {
apiVersion: 3,
// more properties ...
}
Type: boolean
We rely on you to tell us whether we're on a mobile or desktop device type. You can use any kind of device detection you like, but we recommend user agent-based detection, rather than screen size detection.
This existed in KARMA 2.x as: adService.mobileAds
window.karma.config = {
isMobile: !!userAgent.match(/Mobi/) && !userAgent.match(/iPad/), /* true on mobile devices, false on non-mobile */
// more properties ...
}
Type: Array
An array that lists all the slots which will be refreshed.
karma.config.refresh.userInitiated.slotTypes.indexOf('leaderboard:tier1') > -1
Type: string
A string that tells us which site we’re on. This corresponds to the top-level ad unit, and is usually in the form of site.mdp.com/site.mdp.mob. In normal situations, you don’t need to provide this value, as KARMA will attempt to pull it from your hostname via fancy regex. If you’re on a development environment with a weird hostname (like localhost or an IP address), you’ll need to tell KARMA which site you’re on. Note that the value is different per device, so if you’re manually providing it, you’ll need to check the value of karma.config.isMobile to provide the correct string on each device type.
Note that you can also use the adTestSite URL parameter to accomplish this on localhost withou modifying your site code.
This existed in KARMA 2.x as: adService.unitValues.adDomain
karma.config.site = (karma.config.isMobile) ? 'parents.mdp.mob' : 'parents.mdp.com';
Type: object
All page-level targeting key-value pairs are passed in window.karma.config.targeting. You must include the required key-value pairs id, type, and channel, and you may add a number of other free-form key-value pairs, so long as both key and value are:
kw)This existed in KARMA 2.x as: adService.pageTargetingValues, adService.unitValues
window.karma.config = {
targeting: {
id: '12394875', /* REQUIRED */
type: 'article', /* REQUIRED */
channel: 'gardening', /* REQUIRED */
kw: ['chicken', 'frog', 'marshmallow'],
search: '', /* REQUIRED on search pages only */
foo: 'bar', /* add any other key/value pairs */
},
// more properties ...
};
Type: string
A string that uniquely identifies the page that we're on. This enables us to target ads to a particular page, in the event a sponsorship is sold for a given page. Whenever possible, please use the Content Id passed to Google Analytics. Values used for this property must be:
If the GA Content Id is not available we recommend using the URL pathname, with non-alphanumeric characters stripped (unless your URLs are very long, in which case you will need to trim them).
This existed in KARMA 2.x as: adService.pageTargetingValues.id
window.karma.config = {
targeting: {
id: window.location.pathname.substr(1,(window.location.pathname.length < 40 ? window.location.pathname.length : 40)).replace(/\//g, '_').replace(/[^a-z0-9-]/gi, ''),
// more key/values ...
}
// more properties ...
}
Type: string
A string that tells us what kind of page we're on. There is a fixed list of page types. Please select the one that most closely resembles your content.
Standard KARMA page types:
If you have a page type that doesn't fit one of these, please contact a KARMA representative by emailing adsupport@meredith.com.
This existed in KARMA 2.x as: adService.pageTargetingValues.type
window.karma.config = {
targeting: {
type: 'recipe',
// more key/values...
}
// more properties...
}
Type: string
If the ‘type’ is ‘app’, you need to also tell us the name of the application.
This existed in KARMA 2.x as: adService.pageTargetingValues.app_name
window.karma.config = {
targeting: {
type: 'app',
'app_name': 'babynames',
// more key/values ...
}
// more properties ...
}
Type: string
Required on pages with a type of ‘search’ only.
A string that indicates the term the user searched for. This parameter is only required on search results pages where the user has passed in a search term. It can be omitted or set to an empty string on all other pages.
| URL | karma.config.targeting.search |
|---|---|
| http://search.bhg.com/search/s?q=wallpaper | wallpaper |
This existed in KARMA 2.x as: adService.pageTargetingValues.search
window.karma.config = {
targeting: {
search: 'wallpaper',
// more key/values ...
}
// more properties ...
}
Type: string
A string that tells us where this page falls in your site's top-level hierarchy. This existed in KARMA 2.x as: adService.unitValues.channel.
karma.config.targeting.parent
Type: string
A string that tells us where this page falls in your site's second-level hierarchy. This existed in KARMA 2.x as: adService.unitValues.parent.
karma.config.targeting.child
Type: string
A string that tells us where this page falls in your site's third-level hierarchy. This existed in KARMA 2.x as: adService.unitValues.child.
| URL | type | channel | parent | child |
|---|---|---|---|---|
| http://www.bhg.com | homepage | homepage | ||
| http://www.bhg.com/decorating/ | category | decorating | ||
| http://www.bhg.com/decorating/color/ | category | decorating | color | |
| http://www.bhg.com/decorating/color/schemes/ | category | decorating | color | schemes |
| http://www.bhg.com/decorating/color/schemes/gray/ | slideshow | decorating | color | schemes |
| http://www.bhg.com/recipes/ | category | recipes | ||
| http://www.bhg.com/recipes/desserts/ | category | recipes | desserts | |
| http://www.bhg.com/recipes/desserts/cakes/ | category | recipes | desserts | cakes |
window.karma.config = {
targeting: {
type: 'category', /* REQUIRED */
channel: 'recipes', /* REQUIRED */
parent: 'desserts',
child: 'cakes',
// more key/values ...
}
// more properties ...
}
Type: array
If keywords are provided, they should be passed in as an array of strings.
This existed in KARMA 2.x as: adService.pageTargetingValues.kw
window.karma.config = {
targeting: {
kw: ['wallpaper','pasteboard','doilies'],
// more key/values ...
}
// more properties ...
}
Type: string/array
You can pass any other key/value pairs in the karma.targeting object. Both the key and value must be:
These key/value pairs will be passed along to the ad request and can be targeted in GAM line items as custom criteria.
This existed in KARMA 2.x as: adService.pageTargetingValues.foo
window.karma.config = {
targeting: {
foo: 'bar',
// more key/values ...
}
// more properties ...
}
Type: array
If you need a piece of Javascript to run after ads have rendered, use this parameter to pass in an array of functions. These functions will execute after each ad slot is finished rendering.
Each function takes an event parameter that corresponds to GPT’s SlotRenderEnded Event.
Please always use the syntax included in the example, where you initialize the callback array and push into it. This will avoid timing issues with KARMA initialization.
Note that all callbacks will run on each ad slot every time ads are loaded in the slot, so if you have logic that’s specific to a single slot, you will need to check for the correct div id (see example above).
This existed in KARMA 2.x as: adService.callback, where it was sometimes represented as a single function instead of an array. It should always be an array today.
window.karma = window.karma || {};
window.karma.config.callback = window.karma.config.callback || [];
window.karma.config.callback.push(
function(e){ /* I am the first function to run when an ad loads */
if (!e.isEmpty) {
var slot_div_id = e.slot.getSlotId().getDomId;
console.log('this ad has a div id of ' + slot_div_id);
if(slot_div_id == 'div-gpt-leaderboard-flex-1'){
console.log('this is the top leaderboard! Do something leaderboard-y!');
}
}
});
window.karma.config.callback.push(function(e){ /* I am the second function to run when an ad loads */ });
}
Type: boolean
WARNING: You should only set this property to true if you want complete control over when KARMA scrapes the page for ad slots, i.e. if the DOM is dynamically built in a single page application. If you use this, you will also need to manually trigger window.karma.config.go().
window.karma.config = {
bypassDOMReady: true,
// more properties here
}
// later in your site JS, after the initial KARMA init snippet, and once the DOM has been built.
window.karma.config.go();
Type: boolean
Suppresses the automatic addition of div-gpt-interstitial and div-gpt-wallpaper to the page. Add this only if directed by Meredith Ad Product.
window.karma.config = {
suppressInterstitial: true,
// more properties here
}
Type: boolean
Turns on non personalized ads mode in Google Ad Manager to help sites comply with the General Data Protection Regulation (GDPR).
On most Meredith-owned sites, this does NOT need to be manually set, as we have a integration with OneTrust with that will handle consent and the resulting settings automatically. If you do not have a OneTrust integration, you can check/gather consent manually and set this property accordingly.
window.karma.config = {
euPrivacy: {
enabled: true,
}
// more properties here
}
Type: boolean
Turns on restricted data processing mode in Google Ad Manager to help sites comply with the California Consumer Privacy Act (CCPA).
On most Meredith-owned sites, this does NOT need to be manually set, as we have a integration with OneTrust with that will handle consent and the resulting settings automatically. If you do not have a OneTrust integration, you can check/gather consent manually and set this property accordingly.
window.karma.config = {
usPrivacy: {
enabled: true,
}
// more properties here
}
window.karma.config.onPageSettings window.karma.config.staticThese values are merged into a final object that is the one that's in use by KARMA. To inspect that, look at window.karma.config or use the config tab of the KARMA bookmarklet
Here are some common questions and pitfalls we encounter when doing a site integration.
If you received a mapping document from the Meredith Ad Product team, it should include a list of placeholders codes. See below for how to interpret those codes. Otherwise, we have a full slot catalog here.
If you received a mapping document, you may see codes indicating which placeholders should go on the page.
If you see div-gpt-slot-type-n:tierx:
This is an instant slot
<div id="div-gpt-slot-type-n" data-tier="x" role="complementary" aria-hidden="true">If you see div-gpt-lazy-slot-type-tierx:
If you have a question about which tier applies to which placeholder on your site, contact a KARMA representative to help you out by emailing adsupport@meredith.com.
<!-- given a code of `div-gpt-leaderboard-flex-1:tier2 -->
<div id="div-gpt-leaderboard-flex-1" data-tier="2" role="complementary" aria-hidden="true">
window.karma.createSlot('div-gpt-lazy-slot-type-tierx', 'containerid', true)
The data-tier attribute is a way to tell us how important and/or visible an ad slot is on a given page. Tiers go from 1 to 4.
This is referred to as a lazy load ad, and you will use our createSlot method to create it with Javascript.
div-gpt except for the KARMA placeholders. When KARMA loads on a page, it looks for all divs that start with div-gpt and presumes that these are instant slot placeholders. Please don’t use that id pattern for anything else.window.karma.cmd.push().window.karma, apart from configuration values discussed above. KARMA relies on these globally scoped variables in order to do its thing.role="complementary" and aria-hidden="true" attributes on the placeholder div.An ad slot is a spot on the page where an ad renders, denoted with an empty div tag. These divs have unique ids and data attributes that tell us what kind of ad to display.
KARMA supports three types of ad slots:
| Slot type | Slot creation | Ad creative request |
|---|---|---|
| Instant | On Page Load | On page load |
| Lazy Load | Javascript Invoked | Javascript invoked |
| Lazy Scroll | On Page Load | On scroll into view threshhold |
The placeholder divs have three major properties:
id="div-gpt-leaderboard-flex-1"data-tier="1"data-lazy-scroll="true"<!-- instant ads -->
<div id="div-gpt-leaderboard-flex-1" data-tier="1" role="complementary" aria-hidden="true"></div>
<div id="div-gpt-leaderboard-flex-2" data-tier="2" role="complementary" aria-hidden="true"></div>
<!-- lazy scroll ads -->
<div id="div-gpt-square-flex-1" data-tier="1" data-lazy-scroll="true" role="complementary" aria-hidden="true"></div>
<div id="div-gpt-mob-square-flex-1" data-tier="1" data-lazy-scroll="true" role="complementary" aria-hidden="true"></div>
<!-- lazy load ads -->
<div id="lazy-load-ad-goes-here-1"></div>
<div id="lazy-load-ad-goes-here-2"></div>
<script>
window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){
window.karma.createSlot(
'div-gpt-lazy-square-fixed-tier2',
'lazy-load-ad-goes-here-1',
true
);
window.karma.createSlot(
'div-gpt-lazy-square-fixed-tier3',
'lazy-load-ad-goes-here-2',
true
);
});
</script>
The value of the id on the placeholder div represents the following formula: div-gpt-slottype-sizetype-iterator
div-gpt (on desktop) or div-gpt-mob (on mobile) Please do not have any other divs on the page that start with div-gpt. This will confuse KARMA.div-gpt-square-fixed-1, div-gpt-square-fixed-2A list of supported combinations is in the tables below.
KARMA is expecting to find div tags in the DOM with these specific ids. Changing the id values will result in no ad returned.
<!-- instant ads -->
<div id="div-gpt-leaderboard-flex-1" data-tier="1"></div>
<div id="div-gpt-leaderboard-flex-2" data-tier="2"></div>
<div id="div-gpt-mob-square-flex-1" data-tier="1"></div>
| Container Id | Sizes | Slot Type |
|---|---|---|
| div-gpt-leaderboard-flex(-1) | 728x90, 970x90, 970x250 | leaderboard |
| div-gpt-leaderboard-fixed(-1) | 728x90 | leaderboard |
| div-gpt-leaderboard-responsive(-1) | 728x90,300x250 | leaderboard-responsive |
| div-gpt-square-flex(-1) | 300x250, 300x600, 300x1050 | square |
| div-gpt-square-fixed(-1) | 300x250 | square |
| div-gpt-related(-1) | 700x175 | related |
| div-gpt-halfPage-flex(-1) | 300x250, 300x600 | halfPage |
| div-gpt-halfPage-fixed(-1) | 300x600 | halfPage |
| div-gpt-skyscraper(-1) | 160x600 | skyscraper |
| div-gpt-sponsorLogo | 122x34, 120x75 | sponsorLogo |
| div-gpt-fluid | fluid | fluid |
Note: there are DIFFERENT placeholders for mobile and desktop. Responsive sites should put both placeholders in the markup. KARMA will use the value of karma.config.isMobile to determine which placeholders to fill.
| Container Id | Sizes | Slot Type | Note |
|---|---|---|---|
| div-gpt-mob-banner-flex(-1) | 320x50 | mob-banner | |
| div-gpt-mob-banner-fixed(-1) | 320x50 | mob-banner | |
| div-gpt-mob-adhesive-banner-fixed | 320x50 | mob-adhesive-banner | *Only One Per Page |
| div-gpt-mob-square-flex(-1) | 225x75, 300x250, 320x100 | mob-square | |
| div-gpt-mob-square-fixed(-1) | 300x250 | mob-square | |
| div-gpt-mob-sponsorLogo | 122x34, 120x75 | sponsorLogo | |
| div-gpt-mob-fluid | fluid | fluid |
The data-tier attribute is a way to tell us how important and/or visible an ad slot is on a given page.
Tiers go from 1 to 4. Generally, the top leaderboard and the top square-flex are tier 1 (highly visible when the page first loads), anything at the bottom of the page is tier 4 (not very visible at all), and the others fall somewhere in between.
Click the images below to get an idea of how tiers break down on a typical Meredith site.
| Desktop | Mobile |
|---|---|
|
|
Note: the iterator number on the end of the placeholder id and the tier value do not necessarily correlate. The former is a unique slot identifier; the latter is a tier identifier.
<div id="div-gpt-leaderboard-flex-1" data-tier="1"></div>
<div id="div-gpt-square-flex-1" data-tier="1"></div>
<div id="div-gpt-square-fixed-1" data-tier="2"></div>
<div id="div-gpt-mob-square-flex-1" data-tier="1"></div>
If you include data-lazy-scroll="true" as a property on your instant placeholder div, the ad will be defined on page load, but won't be requested/filled until the ad scrolls into view.
There is a threshold defined in the KARMA Config (karma.config.lazyScrollThreshold) that determines how far away from the lazy scroll ad we start filling it.
<!-- lazy scroll ads -->
<div id="div-gpt-square-flex-1" data-tier="1" data-lazy-scroll="true"></div>
Any ad slot can also be lazy loaded via Javascript using the KARMA createSlot API method. When requesting an ad via the createSlot method, you will need to pass the prefix, slot type, size type, and tier, as well as the id or DOM node of the place where the ad should be injected. You do not need to pass the iterator.
More details on all the createSlot options here.
<!-- instant load a tier 2 leaderboard-flex -->
<div id="div-gpt-leaderboard-flex-1" data-tier="2"></div>
<!-- lazy load a tier 2 leaderboard-flex -->
<div id="lazy-load-ad-goes-here-1"></div>
<script>
window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){
window.karma.createSlot(
'div-gpt-lazy-leaderboard-flex-tier2',
'lazy-load-ad-goes-here-1',
true
);
});
</script>
When KARMA loads, it detects whether or not the placeholder divs are hidden by site CSS. If the div is not visible, KARMA will not request the ad. You can take advantage of this functionality to display different desktop ads on medium vs. large breakpoints.
<!-- this placeholder is visible; the ad will be requested -->
<div id="div-gpt-leaderboard-flex-1" data-tier="1"></div>
<!-- this placeholder is hidden; the ad will not be requested -->
<div id="div-gpt-square-flex-1" data-tier="1" style="display:none"></div>
Execute a function after KARMA has initialized and made the initial ad request. We recommend that you push all KARMA API calls into karma.cmd, to rule out any problems with timing (if your code loads before KARMA does, for instance).
| argument | type | description |
|---|---|---|
| fn | function | required - the function to be fired after the ad request returns |
Please always use the syntax included in the example, where you initialize the cmd array and push into it. This will avoid timing issues with KARMA initialization.
window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){
alert('ads ahoy!');
});
Create a lazy loaded slot and inject it into an existing DOM element on the page.
karma.createSlot(slotName, container, autofill, callback, options)
| argument | type | description |
|---|---|---|
| slotName | string | required - The type of slot to build. Check the appendix for a full list of slots. If you are adding a tiered slot, append ‘-tierx’ (where x is the tier number) to the end of your slot name. |
| container | string / DOM element | required - This is either a reference to the DOM object that will contain the new ad slot, or if you pass in a string, the ID of the element with will contain the new ad. This container’s id should not start with ‘div-gpt’, to avoid confusing KARMA. |
| autofill | boolean | optional
- Set to true (default), the slot will instantly fill with an ad. Set to false, you will have to call
karma.fillSlots()
to fill unfilled slots. It is recommended to set this to false if you will be requesting multiple slots at once. |
| callback | function | optional - A function to execute after GPT returns an ad. This is useful if you need the size of the slot. You can pass in an argument (e) into the callback and reference e.size to retrieve the size of the returned ad slot. Note: This callback will fire on subsequent calls to refresh the newly created ad slot. |
| options | object | optional
- An object containing additional options as key/value pairs.
Potential options: refreshable
(boolean) - adds the newly created slot to the list of slots to be refreshed on user-initiated refresh.
purgeRefreshList
(boolean) - purges the list of refreshable slots before adding any new slots.
Note: This argument can be passed as either the fourth or the fifth argument. If you’re passing in a callback, it’ll be fifth. If you have no callback to pass in, you can substitute options instead of callback, and it should work just fine. |
This existed in KARMA 2.x as: adService.renderAds.createLazyLoadSlot(), adService.renderAds.createInfiniteScrollSlot()
window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){
/* this tier 1 flexible square will be soft refreshable */
window.karma.createSlot(
'div-gpt-lazy-square-flex-tier1',
'rightColumn',
true,
function(e){
console.log('A new flex square has been created!'+
'The dimensions of the returned ad are ' + e.size);
},
{ refreshable: true, purgeRefreshList: false});
});
window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){
var rightColumn = document.getElementById('rightColumn');
/* this slot will be soft refreshable */
window.karma.createSlot(
'div-gpt-lazy-square-flex-tier2',
rightColumn,
true,
{ refreshable: true }
);
/* this slot will not be soft refreshable */
window.karma.createSlot(
'div-gpt-lazy-square-fixed-tier3',
rightColumn,
true,
function(){
console.log('This callback will fire only once'+
' the new ad has been filled');
}, { refreshable: false }
);
});
Remove a slot from the page.
karma.destroySlot(slotId)
| argument | type | description |
|---|---|---|
| slotId | string | required - the DOM id of the slot to be destroyed |
This existed in KARMA 2.x as: adService.renderAds.destroySlot()
window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){
window.karma.destroySlot('div-gpt-square-fixed-1');
window.karma.destroySlot('div-gpt-lazy-square-fixed-3');
});
Fills all unfilled slots with a single ad request. This is recommended performance practice if you're adding more than one lazy loaded slot at a time, to save on HTTP requests.
This existed in KARMA 2.x as: adService.renderAds.fillLazyLoadSlots()
window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){
// create two lazy load slots, but wait to fill them
window.karma.createSlot(
'div-gpt-lazy-square-fixed-tier1',
document.body,
false
);
window.karma.createSlot(
'div-gpt-lazy-square-flex-tier2',
document.body,
false
);
// request both lazy slots at once
window.karma.fillSlots();
});
Returns a KARMA slot object.
karma.getSlotById(slotId)
| argument | type | description |
|---|---|---|
| slotId | string | required - The ID of the requested slot. |
If no valid ID is provided, undefined will be returned.
window.karma.getSlotById('div-gpt-leaderboard-flex-1'); //returns the slot object.
Returns an integer. Get the total number of slots registered for this page.
This existed in KARMA 2.x as: adService.renderAds.getSlotCount()
window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){
var slotCount = window.karma.getSlotCount();
console.log('There are '+slotCount+' ad slots on the page.');
});
Is the given slot in view? Returns a boolean.
karma.isInView(slotId, bypassFocusRules)
| argument | type | description |
|---|---|---|
| slotId | string | required - the DOM id of the ad slot placeholder |
| bypassFocusRules | boolean | bypass the check that looks to see if the window is currently focused. This is handy in console-based testing. |
This existed in KARMA 2.x as: adService.renderAds.isInView()
window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){
var isSquareFlex1InView = window.karma.isInView('div-gpt-square-flex-1');
console.log('Is the first square-flex in view? ' + isSquareFlex1InView);
});
/* OR, from the console, bypass focus checking rules */
window.karma.isInView('div-gpt-square-flex-1', true)
Pass reporting info to segment.
karma.report(name, value)
| argument | type | description |
|---|---|---|
| name | string | required - name of the event being tracked |
| value | string, int | required - value of the event being tracked |
karma.report('CollapseCode', 1234567890) // Example of Collapse Code reporting the creative id that called it.
Update page or slot-level targeting values.
karma.updateTargeting(newTargetingObj, slotId)
| argument | type | description |
|---|---|---|
| newTargetingObj | object | required - an object containing key/value targeting pairs |
| slotId | string | optional - if updating a slot, a string representing the DOM ID of the ad slot to update. if updating the page, leave this off |
This existed in KARMA 2.x as: adService.renderAds.updatePageTargeting(), adService.renderAds.updateSlotTargeting()
window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){
// update page-level targeting
window.karma.updateTargeting({'mypagekey': 'myNewPageValue', 'myfoo': 'myNewBar'});
// update targeting on a slot
window.karma.updateTargeting({'myslotkey': 'myNewSlotValue'}, 'div-gpt-lazy-leaderboard-flex-1');
});
Disable timed refresh on a given slot.
karma.disableTimedRefreshOnSlot(slotId, permanent)
| argument | type | description |
|---|---|---|
| slotId | string | required - the DOM id of the ad slot placeholder |
| permanent | boolean | Set to true for permanent disable, set to false or leave undefined to 'pause' the timer to reseume later via reEnableTimedRefrehOnSlot |
This existed in KARMA 2.x as: adService.renderAds.disableTimedRefreshOnSlot()
// permanently disable timed refresh on a slot
window.karma.disableTimedRefreshOnSlot('div-gpt-lazy-square-fixed-3', true);
// temporarily disabled timed refresh on a slot
window.karma.disableTimedRefreshOnSlot('div-gpt-square-fixed-1');
Re-enabled timed refresh on a given slot.
karma.reEnableTimedRefreshOnSlot(slotId)
| argument | type | description |
|---|---|---|
| slotId | string | required - the DOM id of the ad slot placeholder |
// re-enable timed refresh on a slot
window.karma.reEnableTimedRefreshOnSlot('div-gpt-square-fixed-1');
Undock any KARMA-docked leaderboards. (We plan to update this to include rail docking as well in the near future.)
This existed in KARMA 2.x as: adService.renderAds.forceReleaseBanner()
window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){
window.karma.releaseDocking();
});
Re-inititalizes rail docking (after a new piece of content is injected onto the page, for instance). For more details, see our rail docking documentation
window.karma.rebuildRails();
Triggers a user-initiated refresh (for example, when a user clicks to the next slide in a slideshow). The slot types that are eligible for user-initiated refresh can be inspected at window.karma.config.refresh.userInitiated.slotTypes.
This existed in KARMA 2.x as: window.refreshAdFrame()
window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){
window.karma.refresh();
});
Setting bypassViewabilityRequirement to true on a slot will allow it to timed refresh even if the slot is not in the viewport, or if it is covered by another DOM element. This setting does not bypass window focus rules. No slot will timed refresh if the browser window containing that slot is not focused.
karma.setBypassViewabilityRequirement(slotId, true)
| argument | type | description |
|---|---|---|
| slotId | string | required - the DOM id of the ad slot placeholder |
| bypassViewabilityRequirement | boolean | bypass the check that looks to see if a slot is scrolled into view and not covered by another DOM object. |
window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){
window.karma.setBypassViewabilityRequirement('div-gpt-leaderboard-flex-1', true);
});
Add a function to the list of functions that run after each slot is rendered.
Each function takes an event parameter that corresponds to GPT’s SlotRenderEnded Event.
karma.config.callback.push(fn)
| argument | type | description |
|---|---|---|
| fn | function | required - the function to be added to the slot callback stack |
Please always use the syntax included in the example, where you initialize the callback array and push into it. This will avoid timing issues with KARMA initialization.
Note that all callbacks will run on each ad slot every time ads are loaded in the slot, so if you have logic that’s specific to a single slot, you will need to check for the correct div id (see example above). It is good practice to write your callbacks in such a manner that they only execute once.
Each callback that we add that does minimal operations (such as reading and/or variables) consistently adds about .8 ms per slot in the request to the slotOnLoad time. This number increases to ~2ms when DOM lookups are included in the callback (via document.querySelector()).
This existed in KARMA 2.x as: adService.renderAds.addToCallbackList
window.karma = window.karma || {};
window.karma.config.callback = window.karma.config.callback || [];
window.karma.config.callback.push(
function(e){ /* I am the first function to run when an ad loads */
if (!e.isEmpty) {
var slot_div_id = e.slot.getSlotId().getDomId;
console.log('this ad has a div id of ' + slot_div_id);
if(slot_div_id == 'div-gpt-leaderboard-flex-1'){
console.log('this is the top leaderboard! Do something leaderboard-y!');
}
}
});
window.karma.config.callback.push(function(e){ /* I am the second function to run when an ad loads */ });
}
Manually trigger the KARMA init process. Using this method is optional unless karma.config.bypassDOMReady is set to true.
When using KARMA 3, by default the page is scraped for instant slots when the DOMContentLoaded event fires. If DOMContentLoaded has already fired by the time KARMA is ready to scrape the page (i.e. doc.readyState !=='loading') then the page is scraped at that point.
In order to jump start the scraping of the page, karma.config.go() can be called to start slot scraping prior to the DOMContentLoaded event firing. No additional configuration is required to use karma.config.go(). If it is fired after DOMContentLoaded it is ignored, and if it is before, then DOMContentLoaded is ignored (see oneTimeCallbackTrigger() inside dom.js).
The one exception is if karma.config.bypassDOMReady is set to true. In this case, karma.config.go() must be called as KARMA ignores the state of the DOM.
Note: window.karma.config.go is defined in the minified KARMA initial load snippet, so your call to window.karma.config.go() must be included after that definition.
<!-- If used, the call to go() should be placed after the last slot on the page. This tells KARMA that all slots are on the page and the DOM is ready to be processed. -->
<div id="div-gpt-square-fixed-3" data-tier="4" role="complementary" aria-hidden="true"></div>
<script>
karma.config.go();
</script>
Clear header bidding targeting and reset the video targeting object (window.karma.vars.videoTargeting). This method should be called after a video ad request has been sent to GAM containing header bidding targeting. Header bidding targeting is valid for one impression and must be cleared after it is used.
Video targeting is stored on window.karma.vars.videoTargeting where it can be picked up by the video player at the time of the ad request.
karma.resetVideoTargeting()
Request new video ad bids. This function does not accept a callback, so it is reccomended that it be called 5 seconds before an upcoming video ad request is made. This is intended to be used for subsequent videos in a video playlist.
Video targeting is stored on window.karma.vars.videoTargeting where it can be picked up by the video player at the time of the ad request.
karma.updateVideoTargeting()
Events emitted by KARMA in the lifecycle of your page.
Fires when KARMA has finished processing page-level targeting. If you are sniffing for KARMA page types in your code, this would be a good thing to listen for.
Note: this event fires before the ad request has been made.
window.karma = window.karma || {};
window.karma.vars = window.karma.vars || {};
if (!window.karma.vars.targetingReady) { // Targeting is not ready
if (typeof window.dispatchEvent === 'function') { // Check for event support in the browser
window.addEventListener('karmaTargetingReady',function(){
// do the thing once targeting is ready!
console.log('karmaTargetingReady has been fired!!');
});
} else { // browser does not support events
// you can choose to do the thing or not, since you can't rely on targeting being ready
console.log('window.dispatchEvent is not a thing!!');
}
} else { // targeting is ready
// go ahead and do the thing!
console.log('karmaTargetingReady has already been fired!!');
}
Fires when the leaderboard is docked to the top of the page.
document.body.addEventListener("leaderboard_docked", function() {
console.log("The leaderboard is now docked.");
});
Fires when the leaderboard is in the process of undocking from the top of the page.
document.body.addEventListener("leaderboard_undocking", function() {
console.log("The leaderboard is now undocked.");
});
Fires when the leaderboard docking is released.
document.body.addEventListener("leaderboard_undocked", function() {
console.log("The leaderboard is now undocked.");
});
Fires on window immediately before any KARMA request is made to GAM. Event.detail will return a stringified JSON containing a map of the slots being requested (slotContainer), and how they were requested (refreshType);
Note: This event only returns info for the slots that are acutally being sent to GAM. For example, any slots that are hidden at the time of request, thus not sent to GAM will not be returned in the event.
karmaRequest event<script>
window.addEventListener('karmaRequest',function(evt){
console.log(evt.detail);
});
karma.refresh(['div-gpt-leaderboard-flex']);
// Log output --> "[{"slotContainer":"div-gpt-leaderboard-flex","refreshType":"soft"}]"
<script>
KARMA listens for this event to disable timed refresh on a particular slot. This is used instead of (karma.disableTimedRefreshOnSlot)[karmadisabletimedrefreshonslot] in Google Ad Manager when the creative is served inside a cross-domain iframe (aka safeframe).
<script>
parent.postMessage('{"msg":"karmaStopRefresh","slot":"%%PATTERN:slot%%"}','*');
</script>
Fires when the initial ad request has been made.
This is a method, not an event, but if you want to delay any of your code until after KARMA has been initialized and the initial ad request has been made, you will want to wrap your code in karma.cmd.push
Fires when ad creative is returned for each slot.
Like karma.cmd.push above, this is a method, not a event. But if you want to run code after ad creative is returned for each slot, you will want to push it into karma.config.callback.
Functions pushed into karma.config.callback will be executed as a GPT slotRenderEnded event. An argument will be passed into the function that gives you access to the GPT Slot Object via the .slot property (see example).
window.karma = window.karma || {};
window.karma.config = window.karma.config || {};
window.karma.config.callback = window.karma.config.callback || [];
window.karma.config.callback.push(function(e){
var slotId = e.slot.getSlotElementId();
console.log('This is the slot id!', slotId');
});
KARMA has the ability to report on specific events.
KARMA has 2 functions to report on creative wrapper behavior.
Reports to segment when collapse code has been called. This function is called from the collapse code creative wrapper, and passed the creativeId for tracking in BigQuery
Reports to segment when refresh kill code has been called. This function is called from the creative when refresh has been killed, and it passes the creativeId for tracking in BigQuery
karma.report('CollapseCode', creativeId);
karma.report('KillCode', creativeId);
PLEASE NOTE: You can only use the KARMA 3 integration OR the KARMA 2 integration. A horrible Frankenstein's-monster amalgamation of both WILL NOT WORK.
KARMA recently underwent a major API overhaul, known interally as KARMA 3. As of right now, it is basically functionally identical to previous versions of KARMA, and it's fully backwards compatible. Everyone should upgrade their integration to KARMA 3 to take advantage of future functionality releases.
K3 Benefits
TL;DR
window.adService config property names have all changedadService.renderAds and all other API methods have changed. (You can start using the new API Methods immediately, even if your config snippet has not been updated.)<html>
<head>
<!-- The KARMA config code now lives in the head! -->
<script>
window.karma = window.karma || {};
/* --- all these property names have changed */
window.karma.config = {
apiVersion: 3,
isMobile: false,
site: 'bhg.mdp.com',
targeting: {
id: '12394875',
type: 'article',
channel: 'gardening',
kw: ['chicken', 'frog', 'marshmallow'],
search: '',
foo: 'bar',
},
};
/* --- the way you add slot callbacks has changed */
window.karma.config.callback = window.karma.config.callback || [];
window.karma.config.callback.push(function(){ /* a function that runs every time an ad renders */ });
/* --- The KARMA adblock detection/library load snippet now lives in the head, and the path to the file has changed */
!function(a,e){function r(){if(a.karma.vars=a.karma.vars||{},!(a.karma.vars.kismetReported||null!==e.querySelector('img[src$="kismet/spacer.png"]'))){a.karma.vars.kismetReported=!0;var r=e.createElement("img");r.src="/kismet/spacer.png",e.body.appendChild(r)}}a.karma.cmd=a.karma.cmd||[],a.karma.config.go=function(){a.karma.cmd.push("go")};var t=e.createElement("script");t.src="https://karma.mdpcdn.com/service/js-min/karma.js",t.onload=t.onreadystatechange=function(){var a=this.readyState;a&&"complete"!=a&&"loaded"!=a&&r()},t.onerror=r;var m=e.getElementsByTagName("script")[0];m.parentNode.insertBefore(t,m)}(window,document);
</script>
</head>
<body>
<div id="div-gpt-leaderboard-flex-1" data-tier="1" role="complementary" aria-hidden="true"></div>
<div id="div-gpt-mob-square-flex-1" data-tier="1" role="complementary" aria-hidden="true"></div>
</body>
</html>
Get details on all the config properties here.
| Property | Value | Notes |
|---|---|---|
window.karma.config.apiVersion |
3 |
Required for all KARMA 3 integrations |
window.karma.config.bypassDOMReady |
true
/
false |
Only used in special cases |
Get details on all the config properties here.
| If you have this | Change it to this | Notes |
|---|---|---|
window.adService |
window.karma |
|
window.adService.allTiersAllTheTime |
remove | no longer needed |
window.adService.mobileAds |
window.karma.config.isMobile |
|
window.adService.unitValues.adDomain |
window.karma.config.site |
|
window.adService.unitValues.* |
window.karma.config.targeting.* |
All
adService.unitValues
properties other than
adDomain
are now properties of
window.karma.config.targeting |
window.adService.pageTargeting |
window.karma.config.targeting |
All
adService.pageTargeting
properties are now properties of
window.karma.config.targeting |
window.adService.callback |
window.karma.config.callback |
Must be added with
window.karma.config.callback.push |
You can start using the new API methods immediately, even if your config snippet has not been updated.
Get details on all the API methods here.
| If you call this | Change it to this |
|---|---|
window.adServiceQ |
window.karma.cmd |
window.adServiceQ.push |
window.karma.cmd.push |
window.adService.renderAds.addToCallbackList |
window.karma.config.callback.push |
window.adService.renderAds.createLazyLoadSlot |
window.karma.createSlot |
window.adService.renderAds.createInfiniteScrollSlot |
window.karma.createSlot |
window.adService.renderAds.destroySlot |
window.karma.destroySlot |
window.adService.renderAds.fillLazyLoadSlots |
window.karma.fillSlots |
window.adService.renderAds.fillInfiniteScrollSlots |
window.karma.fillSlots |
window.adService.renderAds.getSlotCount |
window.karma.getSlotCount |
window.adService.renderAds.updatePageTargeting(targetingObj) |
window.karma.updateTargeting(targetingObj) |
window.adService.renderAds.updateSlotTargeting(targetingObj) |
window.karma.updateSlotTargeting(targetingObj, slotId) |
window.adService.renderAds.disableTimedRefreshOnSlot |
window.karma.disableTimedRefreshOnSlot |
window.adService.renderAds.isInView |
window.karma.isInView |
window.refreshAdFrame |
window.karma.refresh |
window.adService.renderAds.purgeRefreshSlots |
Use the
purgeRefreshList
option on
window.karma.createSlot
instead. |
window.adService.renderAds.addToRefreshSlots |
Use the
refreshable
option on
window.karma.createSlot
instead. |
window.adService.renderAds.buildDefaultRefreshSlots |
Remove. No replacement. |
window.adService.renderAds.removeFromRefreshSlots |
Remove. No replacement. |
window.adService.renderAds.lazyLoadSLotsFillQueue |
window.karma.vars.slotFillQueue |
Technically, these have all been gone for years. But some of you are still using them. Stop it, please.
Get the full list of slot placeholders here.
| If you have this | Instant slot replacement | Lazy slot replacement |
|---|---|---|
| div-gpt(-lazy)-pushdownBanner | div-gpt-pushdown-flex-n:tierx | div-gpt-lazy-pushdown-flex-tierx |
| div-gpt(-lazy)-topBanner | div-gpt-leaderboard-flex-1:tier1 | div-gpt-lazy-leaderboard-flex-tier1 |
| div-gpt(-lazy)-narrowTopBanner | div-gpt-leaderboard-fixed-1:tier1 | div-gpt-lazy-leaderboard-fixed-tier1 |
| div-gpt(-lazy)-bottomBanner | div-gpt-leaderboard-fixed-n:tier4 | div-gpt-lazy-leaderboard-fixed-tier4 |
| div-gpt(-lazy)-rightBanner | div-gpt-square-flex-1:tier1 | div-gpt-lazy-square-flex-tier1 |
| div-gpt(-lazy)-shortRightBanner | div-gpt-square-fixed-n:tierx | div-gpt-lazy-square-fixed-tierx |
| div-gpt(-lazy)-shopRightBanner | div-gpt-square-fixed-n:tierx | div-gpt-lazy-square-fixed-tierx |
| div-gpt(-lazy)-rightBannerLower | div-gpt-square-fixed-n:tier3 | div-gpt-lazy-square-fixed-tier3 |
| div-gpt(-lazy)-rightBannerLower301 | div-gpt-square-fixed-n:tier3 | div-gpt-lazy-square-fixed-tier3 |
| div-gpt(-lazy)-rightBannerLower302 | div-gpt-square-fixed-n:tier4 | div-gpt-lazy-square-fixed-tier4 |
| div-gpt(-lazy)-tertiarySquare | div-gpt-square-fixed-n:tier3 | div-gpt-lazy-square-fixed-tier3 |
| div-gpt(-lazy)-quaternarySquare | div-gpt-square-fixed-n:tier3 | div-gpt-lazy-square-fixed-tier3 |
| div-gpt(-lazy)-ancillary | div-gpt-square-fixed-2:tier2 | div-gpt-lazy-square-fixed-tier2 |
| div-gpt(-lazy)-mob-nativeInStream | div-gpt-mob-square-fixed-n:tierx | div-gpt-lazy-mob-square-fixed-tierx |
| div-gpt(-lazy)-mob-inStreamBanner | div-gpt-mob-square-fixed-n:tierx | div-gpt-lazy-mob-square-fixed-tierx |
| div-gpt(-lazy)-mob-topBanner | div-gpt-mob-banner-fixed-n:tier1 | div-gpt-lazy-mob-banner-fixed-tier1 |
| div-gpt(-lazy)-mob-bottomBanner | div-gpt-mob-banner-fixed-n:tier4 | div-gpt-lazy-mob-banner-fixed-tier4 |
| div-gpt(-lazy)-mob-hoverBanner | div-gpt-mob-adhesive-banner-fixed-1:tier1 | div-gpt-lazy-mob-adhesive-banner-fixed-tier1 |
Note: -n and :tierx are not literal strings. See how do I translate a KARMA mapping code?
The docking banner functionality for both leaderboards and rails can now be handled by Karma. When docking is turned on, the class 'docked' will be added to the specified container. The site team can then handle the CSS as they need to dock the container.
Docking can be turned on for specific page types, or site wide.
To request leaderboard docking be turned on for a site, please contact the AdDev team and supply the following information, then add the standard docking classes to your page as defined below:
To request rail docking be turned on for a site, please contact the AdDev team and supply the following information, then add the standard docking classes to your page as defined below:
KARMA is expecting these classes to be on the appropriate divs on the page that correspond to our docking needs. These are the network default classes; it can be overridden at the site and page type level. You can see what selectors are configured for the page you're on by looking at karma.config.docking, either in the console, or on the config tab of the KARMA bookmarklet
Leaderboard
Rail
<body class="karma-site-container">
<header>
<div class="karma-leaderboard-docking-element">
<div id="div-gpt-leaderboard-flex-1" data-tier="1"></div>
</div>
</header>
<nav class="karma-below-banner">the element right below the banner</nav>
<!-- rail HTML -->
<div class="karma-content-container">
<div class="karma-main-column">content goes here</div>
<div class="karma-sticky-rail">
<div class="karma-rail-docking-element">
<div id="div-gpt-square-flex-1" data-tier="1"></div>
</div>
</div>
</div>
<div class="full-bleed"></div>
<!-- you can repeat as many content sections with rails as you need -->
<div class="karma-content-container">
<div class="karma-main-column">more content goes here</div>
<div class="karma-sticky-rail">
<div class="karma-rail-docking-element">
<div id="div-gpt-square-flex-1" data-tier="1"></div>
</div>
</div>
</div>
</body>
We have three docking-related events available:
document.body.addEventListener("leaderboard_docked", function() {
console.log("The leaderboard is now docked.");
});
document.body.addEventListener("leaderboard_undocking", function() {
console.log("The leaderboard is now undocked.");
});
document.body.addEventListener("leaderboard_undocked", function() {
console.log("The leaderboard is now undocked.");
});
To release the docked leaderboard, use the releaseDocking API method.
window.karma.releaseDocking();
On pages where rail markup is added to the DOM after page load, once the new content and rail is added, simply call karma.rebuildRails(). This will re-init all pre-existing rails and add any new rails that match the specified class selectors.
Use the rebuildRails API method.
There is an example page with multiple rails and lazy rails here: http://karma.mdpcdn.com/files/docs/examples/desktop-multi-rail.html
window.karma.rebuildRails();
| Situation | Expected Result |
|---|---|
| Leaderboard Docking not enabled in KARMA | Leaderboard does not dock |
| Leaderboard Docking enabled, selectors not configured in KARMA | Leaderboard does not dock |
| Leaderboard Docking enabled, selectors configured in KARMA, site structure matched configuration | Leaderboad is docked |
| Leaderboard Docking enabled, selectors configured in KARMA, site structure did not match configuration | Leaderboard does not dock |
| Leaderboard Docking is disabled due to ad creative calling the releaseDocking method | Leaderboard does not dock |
| Leaderboard Docking is disabled due to the site calling the releaseDocking method | Leaderboard undocks |
| Leaderboard Docking is configured to roll up | Leaderboard is docked, and rolls up after a certain amount of time on-screen |
| Leaderboard Docking is configured to not rollup | Leaderboard is docked, and does not roll up |
| Leaderboard Docking enabled, but creative is oversized | Leaderboard does not dock |
| Rail Docking not enabled | Rail does not dock |
| Rail Docking enabled, but selectors not configured in KARMA | Rail does not dock |
| Rail Docking enabled, selectors configured in KARMA, site structure matched configuration | Rail is docked |
| Rail Docking enabled, selectors configured in KARMA, site structure did not match configuration | Rail does not dock |
| Multi-rail docking not enabled | The first rail docks. All other rails do not dock. |
| Multi-rail docking enabled, but selectors not configured in KARMA | The first rail docks. All other rails do not dock. |
| Multi-rail Docking enabled, selectors configured in KARMA, site structure matched configuration for all rails | All rails are docked |
| Multi-rail Docking enabled, selectors configured in KARMA, site structure matched configuration for some rails | Some rails are docked |
| Multi-rail Docking enabled, selectors configured in KARMA, site structure did not match configuration for any rails | All rails do not dock |
| Multi-rail Docking enabled, selectors configured in KARMA, site structure matched configuration for all rails, site lazy loads an additional rail and invokes rebuildRails method | All rails are docked |
If you include a div-gpt-mob-adhesive-banner-fixed on the page, you also need to include a container div and some CSS for positioning.
<style>
#mobileHoverBannerWrapper {
position: fixed;
bottom: 0;
width: 320px;
left: 50%;
margin-left: -160px;
z-index: 450;
}
</style>
<div id="mobileHoverBannerWrapper">
<div id="div-gpt-mob-adhesive-banner-fixed" data-tier="1" role="complementary" aria-hidden="true"></div>
</div>
KARMA has two mechanisms for refreshing the ads on page: user-initiated refresh and timed refresh.
Triggered by site code when the user takes an action, such as navigating through a slideshow. Uses the karma.refresh method.
/* view slot types configured for user-initiated refresh */
console.log(window.karma.config.refresh.userInitiated.slotTypes);
/* refresh the ads */
window.karma.refresh();
Every page has a set of slot types that are configured in the KARMA Config layer to automatically refresh after they've been in view for a certain amount of time.
The refresh timers on each slot pause when the ad scrolls out of view and resume when the ad re-enters the viewport.
A configured slot must meet the following criteria to for timed refresh to trigger:
karma.config.refresh.timed.intervals.refresh (the timer will pause when the ad is out of view, and resume when the ad is back in view)The slot must meet one of the following criteria
karma.config.refresh.timed.unrestrictedTiers)karma.config.refresh.timed.advertiserBlacklist)You can inspect the timed refresh configuration on any given page by looking at the config tab of the KARMA bookmarklet or by inspecting window.karma.config.refresh.timed in your browser console.
/* view timed refresh configuration */
console.log(window.karma.config.refresh.timed);
A neat feature of timed refresh is the ability to automatically swap the current slot to a different tier or slot type after the ad has been in view for a certain amount of time.
This is basically a prepackaged combination of the destroySlot and createSlot.
The swap interval is separate from the timed refresh interval. You can inspect the swap interval by looking at window.karma.config.refresh.timed.intervals.swap.
For instance: on most Meredith sites, the tier 1 mobile adhesive banner is configured to swap to a tier 3 mobile adhesive banner after 15 seconds in view.
| Situation | Expected Result |
|---|---|
| Timed refresh not enabled | Ads do not refresh on the timer |
| Timed refresh enabled, and all slots on the page are eligible | All ads refresh on the timer |
| Timed refresh enabled, and there are some eligible slots on the page | Only eligible ads refresh on the timer |
| Timed refresh enabled, but there are no eligible slots on the page | No ads refresh on the timer |
| Timed refresh enabled, eligible slots, timer disabled due to ad creative calling disableTimedRefreshOnSlot | The disabled ad does not refresh on the timer |
| Timed refresh enabled, eligible slots, timer reenabled due to ad creative calling reEnableTimedRefreshOnSlot | The timer resumes, and the ad is refreshed on the timer |
| Timed refresh enabled, eligible slots, timer not running due to the slot not 100% on-screen | The off-screen ad slot timer is paused, and the ad does not refresh |
| Timed refresh enabled, eligible slots, timer running due to the slot coming back into 100% on-screen | The timer resumes, and the ad is refreshed on the timer |
| Timed refresh enabled, eligible slots, timer paused due to an overlay covering the slot | The covered ad slot timer is paused, and the ad does not refresh |
| Timed refresh enabled, eligible slots, timer re-started due to the overlay closing | The timer resumes, and the ad is refreshed on the timer |
| Timed refresh enabled, eligible slots, timer disabled due to the browser window losing focus | All ad slot timers are paused, and the ads do not refresh |
| Timed refresh enabled, eligible slots, timer re-started due to the browser window gaining focus | The timer resumes, and the ads are refreshed on the timer |
| Timed refresh enabled, eligible slots, standard non-iFrame busting creative returned | The viewabilty check is applied to the GPT inserted iframe |
| Timed refresh enabled, eligible slots, friendly iFrame buster creative returned | The viewability check is applied to the GPT inserted div instead of the iframe |
| Timed refresh enabled, eligible slots, slots are actively docked | The refresh timer continues when the ad slot is not 100% on-screen or covered by an overlay. The timers are still paused when the window does not have focus. |
| Timed refresh enabled, eligible slots, slots are undocked/not docked | The refresh timer is paused when the ad slot is not 100% on-screen or covered by an overlay. |
These are standalone pages that have nothing but KARMA on them.
What to do when you suspect an ad is misbehaving:
Use the KARMA bookmarklet to see what ads have been requested/returned to the page. Take a screenshot of your screen with the bookmarklet active. Send an email to adsupport@meredith.com with the screenshot and the URL of the page you saw the problem on.
Krux SuperTags is a tag management platform that is included by karma.js. It determines what tags to deliver to your page by looking at your domain name to determine what site you’re on. (If you have a non-standard domain for local/staging purposes, you may not be able to use SuperTags in those environments.)
To verify if SuperTags is being loaded/inspect SuperTags code being delivered, run this in your browser console: document.querySelector('.kxhead')
If it returns null, SuperTags is not being loaded. Otherwise, it should return an object that contains all the JS tags being delivered by SuperTags to your page. You can open each tag individually to inspect the code.
If you see a problem with SuperTags code delivery, contact the KARMA dev team at adsupport@meredith.com.
The handy-dandy KARMA bookmarklet:
The KARMA bookmarklet is accessible here: http://karma.mdpcdn.com/files/tools/bookmarklets
Simply drag it to your bookmarks bar and click it on any Meredith page with ads. The bookmarklet is compatible with Chrome (desktop and mobile), Firefox, Safari (desktop and mobile), Edge, and Internet Explorer.
This tab lists out all the ad slots on the page, as well as identifying information for any ads returned, and any slot-level configuration properties. The slots will also be highlighted and outlined in red on the page itself.
The most important feature on this tab is a Create an email report button that lets you easily send an email to adsupport@meredith.com with any problems you might see. We also recommend that you include a screenshot with your email.

This tab lists page-level KARMA configurations, including leaderboard docking, right rail docking, and timed refresh information. It will also tell you if KARMA is not integrated or not ready.

This tab lists out all page and slot-level targeting information, pulled directly from GAM.
Note: You can use this tab on any site with GAM, not just KARMA sites.

This tab includes a handy form for appending KARMA URL parameters to your URL for debugging purposes. Simply select the params you want and click the Reload Page with Params. Note that this will trigger a full page refresh, so you may lose reference to any problematic ad creatives.

Turn on verbose console logging, expose the window.karmads variable to the global scope, and dump the KARMA log to the console. This functionality can also be turned on via the karmaDebug=true URL parameter.
Note: this should NOT be included in regular site code. It's intended for developer debugging in the console only. If you have the KARMA bookmarklet or the KARMA testing bookmarklet up, this method has already been called (though there's no harm in calling it multiple times).
This existed in KARMA 2.x as: adService.performance.showLog(), adService.performance.exposeKarma()
// Do this in your console, NOT in your code
window.karma.debug()
KARMA offers many URL params to help with testing and debugging.
You can also use the debug tab on the KARMA Bookmarklet to add these params if you hate typing.
Replaces normal ad creative with debug creative. Use this to rule out or identify ad creative as the source of a problem
| property | value(s) | example URL |
|---|---|---|
| adTestKeyValues
adTest |
mdpAdDebug,true
true |
http://www.parents.com/baby/?adTestKeyValues=mdpAdDebug,true&adTest=true |
Enable verbose KARMA debugging in the console (KARMA logs will show up in green) and automatically load the KARMA Bookmarklet. If you forgot to put the karmaDebug URL parameter at the end of your URL, and you still need to see the KARMA logs, you can run this in your browser console instead: window.karma.debug()
| property | value(s) | example URL |
|---|---|---|
| karmaDebug | true | http://www.parents.com/baby/?karmaDebug=true |
If you are inside the Meredith network and/or have access to our dev and test environments, you can preview upcoming KARMA changes on our staging environment using the adTestEnv URL parameter. (Accepted values are local, dev, test, and www.) This will pull in the version of KARMA service on the specified environment, as well as the version of the KARMA config deployed to that environment. Useful if you’re working on changes that correspond to a KARMA release that is not yet in production.
| property | value(s) | example URL |
|---|---|---|
| adTestEnv | local
dev test www |
http://www.parents.com/baby/?adTestEnv=test |
Override the karma.config.site value. This can be useful if you are testing on a page that doesn't match the main site's url.
| property | value(s) | example URL |
|---|---|---|
| adTestSite | bhg.mdp.com
ag.mdp.mob etc. |
http://www.parents.com/baby/?adTestSite=bhg.mdp.com |
Adds a page targeting key/value pair of ref_hub that overrides anything set in the KARMA config.
| property | value(s) | example URL |
|---|---|---|
| ref_hub | foo
banana etc. |
http://www.parents.com/baby/?ref_hub=foo |
If any of these are present in the URL query string, a page-level targeting key-value pair of 'urlSrc' is set that matches either psrc, ordersrc, or esrc.
| property | value(s) | example URL |
|---|---|---|
| urlSrc | psrc | http://www.parents.com/baby/?psrc=true |
| urlSrc | ordersrc | http://www.parents.com/baby/?ordersrc=foo |
| urlSrc | esrc | http://www.parents.com/baby/?esrc=bar |
While any key-value pair can be passed through adTestKeyValues, we often use it to force certain ad creative. Here are a list of known advertest values (these change often, so check with Ad Product if one doesn't work).
Force specific products where possible.
| name | URL param | example URL |
|---|---|---|
| Billboard | adTestKeyValues=advertest,billboard | http://www.parents.com/baby/?adTestKeyValues=advertest,billboard |
| Mobile Wrapper | adTestKeyValues=advertest,wrapper | http://www.parents.com/baby/?adTestKeyValues=advertest,wrapper |
| Mobile Reveal | adTestKeyValues=advertest,reveal_adhesion | http://www.parents.com/baby/?adTestKeyValues=advertest,reveal_adhesion |
| Peelback | adTestKeyValues=advertest,peelback_test | http://www.parents.com/baby/?adTestKeyValues=advertest,peelback_test |
| Pushdown | adTestKeyValues=advertest,celtrabb | http://www.parents.com/baby/?adTestKeyValues=advertest,celtrabb |
| Sponsor Logo | adTestKeyValues=advertest,logo | http://www.parents.com/baby/?adTestKeyValues=advertest,logo |
| Sidekick | adTestKeyValues=advertest,QromeSidekick2 | http://www.parents.com/baby/?adTestKeyValues=advertest,QromeSidekick2 |
| Wallpaper Test | adTestKeyValues=advertest,wallpapertest3 | http://www.parents.com/baby/?adTestKeyValues=advertest,wallpapertest3 |
While any key-value pair can be passed through adTestKeyValues, we often use it to force certain ad creative. Here are a list of known advertest values (these change often, so check with Ad Product if one doesn't work).
Force specific vendors to win a bid auction where possible.
Also known as KARMA (see below).
A legacy Java-based e-commerce platform, owned by Oracle, that powers a few legacy Interwoven-driven sites. ATG also houses CRT and subscription/registration pages.
A vendor/platform for building rich media ads for mobile (sort of like Flash is used for desktop).
The percentage of ads that get clicked on.
Campaign Manager.
Client Services Manager
Cost per click.
Cost per million impressions.
Consumer Revenue Transformation. Our internal term for the team/pages that process our online magazine subscriptions/renewals.
The old ad framework provided by Google that we used to use to serve desktop ads.
Doubleclick for Publishers. The software that our ad operations team uses to manage the ads that get served into the GPT ad tags.
Ad Slot
Defined in Operative as platform+locator+size. Each size that can deliver to a set of Ad Units has to be individually set up
Ad Unit
The name and code (within GAM) that is defined by KARMA (example: bhg.mdp.com/tier1/article/gardening)
Drop ID
Sales system numerical unique identifier (currently FT)
Line Items
Individual products that are listed in GAM with the flight dates and associated size, key value, or geo targeting
Locator (Loc)
The Ad Unit or GAM placement defined in Operative. Loc1 = ad unit, Loc2 = placement
Order
A grouping of line items that comprise a purchased campaign
Package
A grouping of products. Products in packages can be "Visible to the CSM; not pushed to GAM", "Visible to the CSM; pushed to GAM" or "Not visible to the CSM; pushed to GAM"
Placement
CSM usage: The product that is put on the plan. Corresponds (usually) to a Site + Size
CM/Ad Tec usage: A grouping of ad units in GAM
Product
The item that CSMs would book on an order, can be made up of multiple Ad Slots
Push (aka Traffic)
The action of taking a line item and approving it, setting it so that it shows up in the production ad server.
Ads that stay fixed to a certain spot on the user's screen as they scroll. Helps viewability.
Blocking and viewability technology. Some agencies wrap their ad creative with it.
A PHP/MySQL-based CMS that powers many of our sites.
Google's Header Bidding product
Blocking and viewability technology. Some agencies wrap their ad creative with it.
A third-party ad vendor that serves ads on both desktop and mobile. This is one of the third parties that can take over an ad slot, preventing GAM ads from showing.
Google Publisher Tags. The ad framework provided by Google that we use currently to serve desktop and mobile ads.
A mobile ad unit that sticks to the bottom of the user's screen as they scroll.
Slots that are included in the HTML markup and requested instantly as the page loads.
An ad that serves into an overlay that covers the site. Usually we use the term "interstitial" to refer to mobile overlays and "interrupter" or "roadblock" to refer to desktop overlays.
An XML-based CMS that's used on many of our legacy sites. Integrates with Java well, hence why we used it with ATG-driven sites.
The Meredith-developed and maintained wrapper for GPT.
Third-party vendor that sells and serves ads for mobile. We currently serve Kargo tags through GPT.
Third-party integration that keeps track of user information and passes that information to GPT to serve ads targeted to that user's demographic. Krux also provides us with a tag manager called Krux Supertag, which we use to load many of our third-party integrations.
Slots that are dynamically created/injected into the page based on a user interaction (scrolling down the page, for instance). This is in contrast to slots that are in the markup when the page loads initially.
Slots that are included in the HTML markup (like instant slots) but are not requested until the user scrolls to where the slot is a certain distance from the viewport. See Lazy Scroll Slots for implementation details.
A third-party provider that serves ad content on desktop and mobile as well as recommended content on the page. This is one of the third parties that can take over an ad slot, preventing GAM ads from showing.
A third-party vendor that provides us with viewability statistics on our ads. It tracks this via tracking pixels that are inserted onto the page as the user interacts with the page.
A third-party provider that serves in-house ads (targeters) as well as registration interrupters/roadblocks.
Advertising that takes the form of sponsored content on our websites. Native advertising usually does not look like an ad. Instead, it mimics the look and feel of content. Selectable Media is one of our providers for this.
A third-party ad vendor that serves into the ancillary slot, often with the header 'More Smart Savings'.
Our future new order management system. It replaces part of Salesforce, all of FatTail, and part or all of RevStream.
A third-party vendor that provides recommended content on the page, often with the header 'You Might Also Like'.
Video ads that runs before video content.ha
A third-party ad vendor that serves ads on both desktop and mobile. This is one of the third parties that can take over an ad slot, preventing GAM ads from showing.
Usually refers to a login/reg screen in an iframe that's centered inside of an overlay that cover's the user's screen. Not to be confused with a roadblock or interstitial ad.
Usually refers to below-the-fold ads that are run-of-network, low-yield. Usually served through AdEx.
Ads that run across the entire network of sites.
An overlay that covers the user's browser window and serves an invitation to register. When logged in, the roadblock does not appear. Not to be confused with a reg overlay or an interstital ad.
A third-party ad vendor; potential replacement for Pubmatic.
A Meredith-owned vendor that serves native advertising as well as registration interrupters (called 'content unlock'). Selectable unlocks usually give the user a choice of creating an account or watching a video to continue to the content underneath the overlay.
A mobile-specific ad product (originally from Kargo, now served directly through GAM) that takes over the header of a mobile site, often changing the color of the logo and any navigation buttons in the header.
A third-party ad-based captcha that asks users to watch a video, then type a word into the box. Gradually being phased out in favor of Selectable Media interrupters.
A third-party ad vendor that serves ads on both desktop and mobile. This is one of the third parties that can take over an ad slot, preventing GAM ads from showing.
An 'exit ad' that appears when the user attempts to leave one of our sites.
A tag manager provided by Krux, which we use to load many of our third-party integrations.
Also referred to as teasers (on CQ). Essentially, these are house ads, targeted to users based on their registration status. Many (if not all) of these are served through Monetate.
Native Ad exchange. We serve their creative through Selectable Media's platform as backfill.
Usually refers to the percentage of our ads that are visible to the user for at least 1 second. Moat is the tool we currently use to track this.
Desktop ads that cover the background of a site, filling up the blank space that surrounds the site content well. These are served via a GAM template.
Full-screen overlay ad that displays a 'tip of the day' and an ad, as well as a 'Continue to Site' link.
A third-party ad vendor that serves ads on both desktop and mobile. This is one of the third parties that can take over an ad slot, preventing GAM ads from showing. Yieldbot also serves the bar that loads at the bottom of some websites, with links to trending content on those sites. This is referred to internally as "Yieldbar". More Info: Yieldbot
A third-party vendor that serves in-stream ads on mobile and tablet. No related to Yieldbot.
A Meredith-specific term to refer to a series of ad products sorted by how much revenue they yield. No relation to Yieldbot (except that Yieldbot can be included in the Yieldstack).