KARMA Integration Guide

KARMA is Meredith's in-house Javascript framework for serving up ads on websites. It functions as 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 seamlessly integrates with third-party revenue partners, requesting real-time bids for programmatic and intent-based premium ad content. KARMA gives sites access to the full suite of Meredith's ad playbook products with minimal technical integration. We also handle important features like timed refresh, dynamic injection of ads, and leaderboard/right rail docking.

To integrate KARMA on your website, you need two pieces:

  1. KARMA config/init JS snippet in the head
  2. KARMA placeholder div tags in the body
<html>
<head>
  <!-- KARMA config/init snippet goes here -->
</head>
<body>
  <!-- KARMA placeholder DIV tags go here -->
</body>
</html>

KARMA config/init snippet

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 configuration values for your site. More details on each property are below in the KARMA config properties section.

Example <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: 'ddm.bhg.com', /* REQUIRED */
  adUnitFormat: 'ddm', /* REQUIRED */
  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 */
  },
};

!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_${window.karma.config.site}.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>

KARMA placeholder div tags

Empty div tags in the HTML that tell us where and what kind of ads should go.

Not sure which placeholder you need? Check out our slot catalog.

Example <body> placeholders:

<!-- this tells KARMA to request a desktop 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

Instant slots are included in the HTML markup of the page, and are requested immediately once KARMA initializes. This is default KARMA behavior. More about instant/lazy/scroll load slots in the slot catalog.

Example instant slot

<div id="div-gpt-square-fixed-1" data-tier="1" role="complementary" aria-hidden="true"></div>

Scroll Load Slots

Scroll load slots are included in the HTML markup, but they are not requested until the user scrolls within a specified pixel threshold (karma.config.scrollLoadThreshold). To make an instant slot into a scroll load slot, add this attribute: data-scroll-load="true".

  • Scroll load slots are requested in batches as set by karma.config.scrollLoadBatchSize.
  • Scroll load slots are treated like instant slots if they are within the threshold at the time of the ad request.

More about instant/lazy/scroll load slots in the slot catalog.

Example scroll load slot

<div id="div-gpt-square-fixed-1" data-tier="1" data-scroll-load="true" role="complementary" aria-hidden="true"></div>

Ad Slot Initialization Timing

By default, KARMA will listen for the DOMContentLoaded event to trigger the scraping of the DOM for ad slots to fill. If you want finer control over the timing of the initial ad request, take a look at the window.karma.config.go() method.

Example Pages

For a fully functioning example of a page that has nothing but KARMA ads on it, see example KARMA pages

On-Page Config Properties

Specific documentation on the on-page KARMA configuration properties follows.

Some config properties are set by the site. Some are set by KARMA.

  • To see the values of KARMA config properties set by the page, inspect window.karma.config.onPageSettings
  • To see the values of KARMA config properties set by the KARMA config layer, inspect window.karma.config.static

These values are merged into a final object that KARMA uses. To inspect that object, look at window.karma.config or use the config tab of the KARMA bookmarklet

Example <head> config/init snippet

window.karma.config = {
  apiVersion: 3, /* REQUIRED */
  isMobile: false, /* REQUIRED */
  site: 'ddm.bhg.com', /* REQUIRED */
  adUnitFormat: 'ddm', /* REQUIRED */
  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 */ });

karma.config.apiVersion - required

Type: number

We support sites using a legacy (v2.x) KARMA integration with a different configuration pattern. We require the apiVersion parameter to let us know that we're on a KARMA 3.x site.

Example: tell KARMA to use KARMA 3 integration rules

window.karma.config = {
  apiVersion: 3,
  // more properties ...
}

karma.config.isMobile - required

Type: boolean

We rely on you to tell us whether we're on a mobile or desktop device type. We recommend user agent-based detection rather than screen size detection.

Example: tell KARMA whether it should fill mobile or desktop ads

window.karma.config = {
  isMobile: !!userAgent.match(/Mobi/) && !userAgent.match(/iPad/), /* true on mobile devices, false on non-mobile */
  // more properties ...
}

karma.config.adUnitFormat - required

Type: string

If your karma.config.site value begins with ddm. or revshare., this property should be set to 'ddm'.

Example: set the ad unit format

window.karma.config = {
  adUnitFormat: 'ddm'
  // more properties ...
}

karma.config.site - required

Type: string

A string that tells KARMA which site we’re on. This corresponds to the top-level ad unit, and is usually in the form of ddm.site.com/ddm.site.mob or revshare.site.com/revshare.site.mob.

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.

Alternatively, you can use the adTestSite URL parameter to accomplish this on a localhost/development URL without modifying your site code.

Example: set the site to Parents (device-aware)

window.karma.config.site = `ddm.parents.${window.karma.config.isMobile ? 'mob' : 'com'}`;

karma.config.targeting - required

Type: object

Contains all page-level targeting key-value pairs. You must include the required key-value pairs id, type, and channel, and you may add other free-form key-value pairs, so long as both key and value are:

  • an alphanumeric string (dashes and underscores are allowed), or an array of strings (like kw)
  • under the character limits (20 characters for keys, 40 characters for values)

Example: set page targeting values

window.karma.config = {
  targeting: { 
    id: '12394875',  /* REQUIRED */
    type: 'structuredcontent', /* REQUIRED */
    channel: 'gardening', 
    kw: ['chicken', 'frog', 'marshmallow'], 
    search: '', /* REQUIRED on search pages only */
    foo: 'bar', /* add any other key/value pairs */
  },
  // more properties ...
};

karma.config.targeting.id - required

Type: string

A string that uniquely identifies the page. This enables us to target ads to a particular page. The id should:

  • be unique to each page
  • contain alphanumeric characters only
  • be less than (or equal to) 40 characters long
  • whenever possible, it should match the Content Id passed to Google Analytics

If the Google Analytics 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).

Example: set page id (generated from URL pathname)

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 ...
}

karma.config.targeting.type - required

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:

  • taxonomy (formerly 'homepage')
  • taxonomysc (formerly 'category')
  • structuredcontent (formerly 'article')
  • listsc (formerly 'slideshow')
  • recipesc (formerly 'recipe')
  • other

Any other values passed in will be mapped to 'other' if they're not in the above list.

KARMA uses this value to build the ad unit, thus it is required.

Example: set page type

window.karma.config = {
  targeting: {
    type: 'recipesc',
    // more key/values...
  }
  // more properties...
}

karma.config.targeting.app_name

Type: string

If your site is an externally-hosted application, you need to tell us the name of the application.

Example: set targeting for an application

window.karma.config = {
  targeting: {
    type: 'other',
    'app_name': 'babynames',
    // more key/values ...
  }
  // more properties ...
}

karma.config.targeting.search

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

Example: set search term targeting on search results pages

window.karma.config = {
  targeting: {
    search: 'wallpaper',
    // more key/values ...
  }
  // more properties ...
}

karma.config.targeting.channel - required

Type: string

A string that tells us where this page falls in your site's top-level hierarchy. KARMA uses this value to build the ad unit, thus it is required.

Example code: set channel targeting

window.karma.config = {
  targeting: {
    channel: 'recipes', /* REQUIRED */
    // more key/values ...
  }
  // more properties ...
}

karma.config.targeting.foo

Type: string/array

You can pass any other key/value pairs in the karma.targeting object. Both the key and value must be:

  • an alphanumeric string (dashes and underscores are allowed), or an array of strings
  • under the character limits (20 characters for keys, 40 characters for values)

These key/value pairs will be passed with the ad request and can be targeted in GAM line items as custom criteria.

Example: set custom page-level targeting

window.karma.config = {
  targeting: {
    foo: 'bar',
    // more key/values ...
  }
  // more properties ...
}

karma.config.refresh.userInitiated.slotTypes

Type: Array

An array containing all the slot types that will be refreshed when user-initiated refresh is triggered via karma.refresh()

Example: see if the tier1 leaderboard will be refreshed

karma.config.refresh.userInitiated.slotTypes.indexOf('leaderboard:tier1') > -1

karma.config.callback

Type: array

If you need Javascript to run after ads have rendered, use this parameter to pass in an array of functionsthat will execute after each ad slot is finished rendering.

For examples and more details, see karma.config.callback.push

karma.config.bypassDOMReady

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().

Example: Manually trigger KARMA load

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();

karma.config.euPrivacy.enabled

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.

Example: enable GDPR compliance on a page

window.karma.config = {
  euPrivacy: {
    enabled: true,
  }
  // more properties here
}

karma.config.usPrivacy.enabled

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.

Example: enable CCPA compliance on a page

window.karma.config = {
  usPrivacy: {
    enabled: true,
  }
  // more properties here
}

Integration FAQ

Here are some common questions and pitfalls we encounter when doing a site integration.

How do I know what placeholders to put on my page?

If you received a mapping document from the Meredith Ad Product team, it should include a list of placeholder codes. Read on to learn how to interpret those codes. Otherwise, we have a full slot catalog here.

How do I translate a KARMA mapping placeholder code?

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

    • ‘n’ is an integer that uniquely identifies the placeholder on the page
    • ‘x’ is an integer that defines the tier for this slot
  • The resulting HTML markup should be: <div id="div-gpt-slot-type-n" data-tier="x" role="complementary" aria-hidden="true">

If you see div-gpt-lazy-slot-type-tierx:

  • This is a lazy slot
  • You should make a call in your site Javascript to karma.createSlot

If you have a question about which placeholder you need on your site, contact a KARMA representative to help you out by emailing adsupport@meredith.com.

Example code/placeholder translation

<!-- 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">

Example lazy slot creation JS

window.karma.cmd.push(function(){
   window.karma.createSlot('div-gpt-lazy-slot-type-tierx', 'containerid', true);
})

What is a tier?

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. More details on tiers here.

How do I load an ad slot after the initial ad request is made?

If you want the slot to load automatically when scrolled into view, add the scroll-load=true attribute.

If you want the slot to be added when the user takes an action (e.g. clicking 'Load More' or navigating through a slideshow), create it with the karma.createSlot Javascript method.

Things to watch out for

  • Do not give any divs the prefix 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.
  • Do not move ad container divs around in the DOM. This is common in masonry layouts and some docking solutions. If you move divs that contain ads around in the DOM, it wipes out the contents of the iframe and causes a ‘no ad returned’ message in the KARMA bookmarklet.
  • Make sure to wrap all KARMA API lazy load ad invocations in window.karma.cmd.push().
  • Do not delete or modify window.karma, apart from configuration values discussed above. KARMA relies on globally scoped variables in order to do its thing.
  • To comply with accessibility requirements, all KARMA placeholder DIVs must include role="complementary" and aria-hidden="true" attributes.

Slot Catalog

An ad slot is an empty div tag on the page where an ad renders. These divs have unique ids and data attributes that tell us what kind of ad to display.

KARMA supports three types of ad slots:

  • instant ads are included in the page's HTML markup and filled as soon as they are requested.
  • scroll load ads are a variant of instant ads that are filled when scrolled into view.
  • lazy load ads are dynamically added to the page by site code with Javascript based on user interaction (see createSlot for more details).
Slot type Slot creation Ad creative request
Instant On Page Load On page load
Lazy Load Javascript Invoked Javascript invoked
Scroll Load On Page Load On scroll into view threshhold

The placeholder divs have three major properties:

  • id, e.g. id="div-gpt-leaderboard-flex-1"
  • tier, e.g. data-tier="1"
  • scroll load, e.g. data-scroll-load="true"

Example:

<!-- 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>

<!-- scroll load ads -->
<div id="div-gpt-square-flex-1" data-tier="1" data-scroll-load="true" role="complementary" aria-hidden="true"></div>
<div id="div-gpt-mob-square-flex-1" data-tier="1" data-scroll-load="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>

KARMA Ad Placeholder IDs

The value of the id on the placeholder div represents the following formula: div-gpt-slottype-sizetype-iterator

  • prefix: this is always 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.
  • slot type: e.g. leaderboard, square, adhesive-banner, fluid
  • size type: fixed, flex, responsive (see tables below)
  • iterator: an integer tacked on to the end of the id that makes it unique, e.g. div-gpt-square-fixed-1, div-gpt-square-fixed-2

A 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>

Desktop Ad Placeholders

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

Mobile Ad Placeholders

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

Note: Additional site CSS is required for the mobile adhesive banner.

Ad Slot Tiers

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
desktop tiers mobile tiers

Note: the iterator number on the end of the placeholder id and the tier value do not correlate. The iterator is a unique slot identifier; the tier value is an indicator of importance.

<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>

Scroll load Ads

Formerly referred to as "lazy scroll" ads.

If you include data-scroll-load="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.scrollLoadThreshold) that determines how far away from the scroll load ad we start filling it.

<!-- scroll load ads -->
<div id="div-gpt-square-flex-1" data-tier="1" data-scroll-load="true"></div>

Lazy Load Ads

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>

Ad Placeholder Visibility

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>

API Methods

karma.cmd.push

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.

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.

Example: run a function after ads come back

window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){  
  alert('ads ahoy!');
});

karma.createSlot

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 and tier of slot to build. Check the slot catalog for a full list of slot types. Append ‘-tierx’ (where x is the tier number) to the slot type. Can be passed with or without the -lazy- subsrting, but once the slot is created the id will reflect that it is lazy. E.g. if you pass div-gpt-square-fixed-tier1 into slotName , the resulting slot ID will be div-gpt-lazy-square-fixed-[x] where x is the incrementor
container string / DOM element required - A reference to the DOM object that the new ad slot will be appended to. You can pass either the DOM object itself or a string denoting the id of the container. (NOTE: This id should NOT start with ‘div-gpt’.)
autofill boolean Set to true (default), the slot will instantly fill with an ad. When set to false , you must call karma.fillSlots() to fill all unfilled slots. We recommend you set autofill to false if you're requesting multiple slots at once.
callback function A function to execute after GPT returns an ad. You can pass in an argument (e) into the callback and reference e.size to retrieve the size of the returned ad creative. This callback will fire again on subsequent calls to refresh the newly created ad slot.
options object An object containing additional options as key/value pairs.

Options:
targeting (object) - targeting key/values specific to the newly created slot.

Note: options 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 .

Example: create and autofill one lazy load slot

window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){ 

  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);
    });

});

Example: create multiple lazy load slots at once

window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){

  var rightColumn = document.getElementById('rightColumn');
  
  window.karma.createSlot(
    'div-gpt-lazy-square-flex-tier2', 
    rightColumn, 
    false,
    { 'targeting': {'foo': 'bar'}}
  );
  
  window.karma.createSlot(
    'div-gpt-lazy-square-fixed-tier3', 
    rightColumn, 
    false, 
    function(){
      console.log('This callback will fire when'+
      ' the new ad has been filled');
    }
  );

  /* request both slots */
  window.karma.fillSlots();

});

karma.destroySlot

Remove a slot from the page.

karma.destroySlot(slotId)

argument type description
slotId string required - the DOM id of the ad slot to be destroyed

Example: remove slots from the page

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');

});

karma.fillSlots

Requests all unfilled slots with a single ad request. We recommend this approach if you're adding more than one lazy-loaded slot at a time.

Example: create two lazy slots with one request

window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){
  
  // create two lazy load slots, then request 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();
  
});

karma.getSlotById

Returns a KARMA slot object. If no slot is found for the id provided, returns undefined.

karma.getSlotById(slotId)

argument type description
slotId string required - the DOM id of the ad slot

Example: Get the leaderboard slot object with an id of 'div-gpt-leaderboard-flex-1'

window.karma.getSlotById('div-gpt-leaderboard-flex-1'); //returns the slot object.

karma.getSlotCount

Get the total number of ad slots on this page. Returns an integer.

Example: get the number of ad slots on the page

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.');

});

karma.isInView

Returns true if the given slot is in view.

karma.isInView(slotId, bypassFocusRules)

argument type description
slotId string required - the DOM id of the ad slot placeholder
bypassFocusRules boolean bypass the check to see if the window is currently focused. This comes in handy when testing in the console.

Example: check whether a given slot is currently in view

window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){

  console.log('Is the first square-flex in view? ' 
    + window.karma.isInView('div-gpt-square-flex-1'));

});

/* OR, from the console, bypass focus checking rules */
window.karma.isInView('div-gpt-square-flex-1', true)

karma.report

Pass reporting info to Segment.

karma.report(name, value, label)

argument type description
name string required - name of the event being tracked
value string, int required - value of the event being tracked
label string label for the event being tracked (default: tracking )

Example: collapse code reporting the creative id that called it

window.karma.report('CollapseCode', 1234567890);

karma.updateTargeting

Update page or slot-level targeting values.

karma.updateTargeting(targetingObj, slotId, isPersistent)

Note: karma.updateTargeting(key, value, slotId, isPersistent) is also valid syntax for setting a single value on a slot.

argument type description
targetingObj object required - an object containing key/value targeting pairs
Note #1: if a targeting value is an empty string or null, that targeting key/value will be cleared off the page/slot.
Note #2: if you have only one key/value to update, you can pass the key as the first argument and the value as the second argument
slotId string if updating a slot, the DOM ID of the ad slot to update. if updating the page, leave this off
isPersistent boolean if updating a slot, should this value persist between refreshes?

Example: update page and slot targeting

window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){

  // update page-level targeting 
  window.karma.updateTargeting({
    'id': 'newPageId', 
    'type': 'newPageType',
    'foo': 'bar',
    'parent': '' // this value will be cleared
  });

  // update targeting on a slot
  window.karma.updateTargeting(
    'foo', 
    'bar'
    'div-gpt-lazy-leaderboard-flex-1',
    true
  );

});

karma.clearTargeting

Clear a single page targeting key/value, or clear a single slot targeting key/value pair

karma.clearTargeting(key, slot)

Note: Passing only a key will clear that key/value from page targeting. Passing a key and a slot will clear that key/value from a slot.

argument type description
key string required - name of the key/value pair you want to remove from targeting
slot object Pass the slot object you want to clear the targeting key/value from

Example: clear slot or page targeting

// Clear page targeting
karma.clearTargeting('foo')

// Clear slot targeting
karma.clearTargeting('foo', karma.getSlotById('div-gpt-leaderboard-flex-1'))

karma.disableTimedRefreshOnSlot

Disable timed refresh on a given slot.

karma.disableTimedRefreshOnSlot(slotId, permanent)

argument type description
slotId string required - the DOM id of the ad slot
permanent boolean If true, disables refresh on the slot permanently, set to true. Leave this undefined to allow re-enabling via karma.reEnableTimedRefrehOnSlot

Click here for more examples

Example: disable timed refresh on a slot.

// permanently disable timed refresh on a slot
window.karma.disableTimedRefreshOnSlot('div-gpt-lazy-square-fixed-3', true);

// temporarily disable timed refresh on a slot
window.karma.disableTimedRefreshOnSlot('div-gpt-square-fixed-1');

karma.reEnableTimedRefreshOnSlot

Re-enabled timed refresh on a given slot.

karma.reEnableTimedRefreshOnSlot(slotId)

argument type description
slotId string required - the DOM id of the ad slot

Example: re-enable timed refresh on a slot

// re-enable timed refresh on a slot
window.karma.reEnableTimedRefreshOnSlot('div-gpt-square-fixed-1');

karma.initDocking

Restart leaderboard docking if it has been previously released.

Example: restart leaderboard docking

// restart leaderboard docking
window.karma.initDocking();

karma.releaseDocking

Undock a KARMA-docked right rail or leaderboard.

karma.releaseDocking(dockingType)

argument type description
dockingType string required - what type of docking to release: 'leaderboard' (default), 'rail' , 'both'

Example: release a docked leaderboard

window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){

  // undock leaderboard
  window.karma.releaseDocking());
  window.karma.releaseDocking('leaderboard');

  // undock rail
  window.karma.releaseDocking('rail');

  // undock leaderboard and rail
  window.karma.releaseDocking('both');

});

karma.rebuildRails

Re-inititalizes rail docking. Commonly used on auto-advance. For more details, see our rail docking documentation

Example: rebuild docked rails

window.karma.rebuildRails();

karma.refresh

Triggers a user-initiated refresh (e.g. when a user clicks to the next slide in a slideshow).

  • You can see the eligible slot types for user-initiated refresh at window.karma.config.refresh.userInitiated.slotTypes.
  • You can see an array of refreshable slots at window.karma.slots.refresh

karma.refresh(slotsToRefresh)

argument type description
slotsToRefresh array optional - a list of slot ids to refresh. Defaults to karma.slots.refresh .

Example: soft-refresh all ad slots configured for user-initiated refresh

window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){

  // trigger user-initiated refresh for all eligible slots
  window.karma.refresh();

  // trigger user-initiated refresh for only the first flexible leaderboard and the second fixed square
  window.karma.refresh([
    'div-gpt-leaderboard-flex-1',
    'div-gpt-square-fixed-2',    
  ]);

});

karma.setBypassViewabilityRequirement

Setting bypassViewabilityRequirement to true on a slot allows it to timed refresh even if the slot is not in the viewport, or if it is covered by another DOM element.

NOTE: This setting does not bypass window focus rules. Slots will not timed refresh if their browser window is not focused.

karma.setBypassViewabilityRequirement(slotId, true)

argument type description
slotId string required - the DOM id of the ad slot
bypassViewabilityRequirement boolean bypass the non-focus viewability checks

Example: allow leaderboard to timed refresh when scrolled out of view or covered by another DOM object

window.karma = window.karma || {};
window.karma.cmd = window.karma.cmd || [];
window.karma.cmd.push(function(){

  // allow timed refresh on the first tier1 leaderboard
  // even when out of view
  window.karma.setBypassViewabilityRequirement('div-gpt-leaderboard-flex-1', true);

});

karma.config.callback.push

Add a function to the list 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

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). It's 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()).

Example: Add a callback that fires when ad slots are done rendering

window.karma = window.karma || {};
window.karma.config.callback = window.karma.config.callback || [];

/* Add function to run when an ad loads */ 
window.karma.config.callback.push( 
  function(e){ 
    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!');
      }
    }
  });
}

karma.config.go

Manually trigger the KARMA init process. Using this method is optional unless karma.config.bypassDOMReady is set to true.

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 immediately.

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 and should be placed after the last slot on the page.

Example: Trigger KARMA load ahead of DOMContentLoaded

<div id="div-gpt-square-fixed-3" data-tier="4" role="complementary" aria-hidden="true"></div>
<!-- karma.config.go is called after the last slot and the KARMA config snippet -->
<script>
  karma.config.go();
</script>

karma.resetVideoTargeting

Clear any targeting set by header bidding partners and reset the video targeting object (window.karma.vars.videoTargeting). This method should be called after a video ad request containing header bidding targeting has been sent to GAM. Header bidding targeting is valid for one impression and must be cleared after it's used.

Video targeting representing bids is stored on window.karma.vars.videoTargeting, where it can be read by the video player at the time of the ad request.

Example: Trigger KARMA load ahead of DOMContentLoaded

// clear previous bid information
window.karma.resetVideoTargeting();

karma.updateVideoTargeting

Request new video ad bids from header bidding partners. This function does not accept a callback, so it is recommended 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 representing bids is stored on window.karma.vars.videoTargeting where it can be picked up by the video player at the time of the ad request.

Example: Request new video bids

// request new bids and store targeting
window.karma.updateVideoTargeting();

Events

Events emitted by KARMA in the lifecycle of your page.

karmaTargetingReady - when page targeting is ready

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 event to listen for.

Note: This event fires before the ad request has been made.

Example: listen for when KARMA targeting is ready

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!!');
}

leaderboard_docked

Fires when the leaderboard is docked to the top of the page.

Example: Listen for KARMA docking events

document.body.addEventListener("leaderboard_docked", function() {
    console.log("The leaderboard is now docked.");
});

leaderboard_undocking

Fires when the leaderboard is in the process of undocking from the top of the page.

Example: Listen for KARMA leaderboard undocking

document.body.addEventListener("leaderboard_undocking", function() {
    console.log("The leaderboard is now undocked.");
});

leaderboard_undocked

Fires when the leaderboard docking is released.

Example: Listen for KARMA docking events

document.body.addEventListener("leaderboard_undocked", function() {
    console.log("The leaderboard is now undocked.");
});

karmaRequest

Fires on window immediately before a 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.

Example: Listen for 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>

karmaStopRefresh

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>

karma.cmd.push

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

karma.config.callback

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).

Example: Execute code on slot render

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 3 Migration Guide

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 underwent a major API overhaul several years ago, known internally as KARMA 3. Everyone should upgrade their integration to KARMA 3 to take advantage of future functionality releases.

K3 Benefits

  • 1 KARMA file instead of 2!
  • Built-in adblock detection!
  • Cleaner API!

TL;DR

Example K3 Integration

<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>

New Config Properties in KARMA 3

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

Changes to Existing Config Properties

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

API Method Changes in KARMA 3

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.destroySlot window.karma.destroySlot
window.adService.renderAds.fillLazyLoadSlots 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 (deprecated) on window.karma.createSlot instead.
window.adService.renderAds.addToRefreshSlots Use the refreshable option (deprecated) 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

KARMA Docking

KARMA handles docking banner functionality for both leaderboards and rails. When docking is turned on, the class 'docked' will be added to the specified 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:

  • KARMA page types to dock the leaderboard on (or all pages)
  • Sample URLs
  • Should the banner roll back up after a specified time?

    • How long? (10 sec default)

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 page types to dock the rail on (or all pages)
  • Sample URLs

Standard Docking Element Classes

KARMA is expecting these classes to be on the appropriate divs on the page.

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

  • dockingElementSelector: '.karma-leaderboard-docking-element'
  • belowBannerSelector: '.karma-below-banner'
  • siteContainerSelector: '.karma-site-container'

Rail

  • dockingElementSelector: '.karma-rail-docking-element'
  • contentContainerSelector: '.karma-content-container'
  • mainColumnSelector: '.karma-main-column'
  • railSelector: '.karma-sticky-rail'

Rails on Grid Layouts

  • dockingElementSelector: '.karma-rail-docking-element'
  • railSelector: '.karma-sticky-rail'

Example: leaderboard/docking rail HTML

<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>

Rail Docking on Grid Layouts

If your page has a grid layout...

Besides the 2 required configurable classes:

  • dockingElementSelector: '.karma-rail-docking-element'
  • railSelector: '.karma-sticky-rail'

You also need to add the class .karma-sticky-grid to the page. It can be added to the grid wrapper, or even just the body. That class allows KARMA to easily know to apply the grid layout rail docking logic.

Docking Events

We have three docking-related events available:

Example: Listen for KARMA docking events

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.");
});

Release Docking

To release a docked leaderboard or rail, use the releaseDocking API method.

Example: release docked leaderboard

window.karma.releaseDocking('leaderboard');

Rebuild Rail Docking

On pages where rail markup is added to the DOM after page load, once the new content and rail is added, call karma.rebuildRails(). This will re-init all pre-existing rails and add any new rails that match the specified class selectors.

There is an example page with multiple rails and lazy rails here: http://karma.mdpcdn.com/files/docs/examples/desktop-multi-rail.html

Example: rebuild docked rails

window.karma.rebuildRails();

Docking Use Cases

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

Mobile Adhesive Banner Styling

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.

Example: mobile adhesive positioning code

<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>

Refresh

KARMA has two mechanisms for refreshing the ads on page: user-initiated refresh and timed refresh.

User-initiated 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();

Timed 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:

  • 100% of pixels are in the active window (clicking into the developer console will make the window inactive)
  • Each of the 4 corners of the ad creative are not covered by any visible HTML elements (e.g. overlays, floating menus)
  • The slot must be in view for at least the length of time specified in 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 ad creative must not have disabled timed refresh via the karma.disableTimedRefreshOnSlot() method

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);

Slot swap

A 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.

Example KARMA Pages

These are standalone pages that have nothing but KARMA on them.

Troubleshooting

What to do when you suspect an ad is misbehaving:

  • Use the KARMA bookmarklet to see what ads have been returned to the page. Take a screenshot of your screen with the bookmarklet active.
  • Click the Create a support ticket button at the top of the slots tab. Attach your screenshot to the issue that is created.
  • If your problem is an issue with bad ad creative, the Ad Product team will contact the campaign manager and/or ad agency to correct the problem.
  • If we determine that your problem has to do with a bug in KARMA itself, the Ad Product team will create a support ticket with the KARMA developers to address the issue.

KARMA Bookmarklet

The handy-dandy KARMA bookmarklet:

  • Lets you inspect site and page-level KARMA configuration properties.
  • Tells you what ad slots have been requested, as well as which ads have been returned.
  • Lets you report problematic ad creative via Jira with one click.
  • Tells you what page and slot targeting values we have passed to GAM.
  • Tells you what page and slot-level configurations are set up for timed refresh, slot swap, and docking.
  • Gives you a handy interface for appending URL params onto your URL for testing/debugging purposes.

The bookmarklet is compatible with Chrome (desktop and mobile), Firefox, Safari (desktop and mobile), and Edge.

Installing the 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.

Auto-launch the KARMA bookmarklet with a URL param

You may also append karmaDebug=true as a URL parameter to any page with KARMA, and the bookmarklet will automatically open.

Example: http://bhg.com/?karmaDebug=true

Slots Tab

The slots tab lists all the ad slots on the page, as well as identifying information for any ad creatives returned, and some 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 a support ticket button that lets you easily create a Jira issue with any ad creative problems you might see. We recommend that you include a screenshot with your ticket.

KARMA bookmarklet: slots tab

Config Tab

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

KARMA bookmarklet: config tab

Targeting Tab

The targeting tab lists all page and slot-level targeting information that was sent to GAM. Slots' possible sizes and ad unit information are also included.

Note: Since these values are pulled directly from GAM, you can use this tab on any site that uses GAM for ads, even non-Meredith sites.

KARMA bookmarklet: targeting tab

Debug Tab

The debug 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 button. Note that this will trigger a full page refresh, so you may lose reference to any problematic ad creatives.

KARMA bookmarklet: debug tab

Debug API Methods

karma.debug

Turns on verbose console logging, exposes the window.karmads variable to the global scope, and dumps 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).

Example: turn on console debugging for KARMA

// Do this in your console, NOT in your code
window.karma.debug()

URL Params

KARMA offers many URL params to help with testing and debugging.

You can use the debug tab on the KARMA Bookmarklet to add these params if you hate typing.

MDP Debug Creative

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

karmaDebug

Set to true to enable verbose KARMA debugging in the console (KARMA logs will show up in green) and automatically load the KARMA Bookmarklet.

If you don't want the bookmarklet to pop up, but you do want verbose logs, set this value to 'log'.

If you forgot to use this URL param, and you still need to see the KARMA logs, you can run this in your browser console instead: window.karma.debug()

description property value(s)
Turn on console debugging and show the bookmarklet karmaDebug true
Turn on console debugging only karmaDebug log

adTestEnv

You can preview upcoming KARMA changes on our staging environment using the adTestEnv URL parameter.

This will pull in the version of KARMA on the specified environment, as well as the version of the KARMA config and KARMA tets 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

adTestSite

Overrides 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

Glossary

A9

Amazon's header bidding framework.

Celtra

A vendor/platform for building rich media ads for mobile (sort of like Flash is used for desktop).

CTR

Click-through rate. The percentage of ads that get clicked on.

CM

Campaign Manager.

CSM

Client Services Manager

CPC

Cost per click.

CPM

Cost per million impressions.

GAM

Google Ad Manager. The software that our ad operations team uses to manage the ads that get served into the GPT ad tags.

GAM Terminology

  • 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.

Docking leaderboard or rails

Ads that stay fixed to a certain spot on the user's screen as they scroll. Helps viewability.

Double Verify (DV)

Blocking and viewability technology. Some agencies wrap their ad creative with it.

Element

A Node.js-based custom platform that powers many of our sites.

First Look

Google's Header Bidding product

FlashTalking (FT)

Blocking and viewability technology. Some agencies wrap their ad creative with it.

GPT

Google Publisher Tags. The ad framework provided by Google that KARMA uses to serve desktop and mobile ads.

Header Bidding

A process by which advertising vendors bid on ad slots on the page. Bids are fetched from the vendors prior to the ad request and are passed as targeting values on the slot.

Index Exchange

A header bidding vendor that is run through Prebid.

Instant ad slots

Slots that are included in the HTML markup and requested instantly as the page loads. More on instant slots

KARMA

The Meredith-developed and maintained Javascript wrapper for GPT.

Lazy Load ad slots

Slots that are dynamically created/injected into the page based on a user interaction (opening a modal, for instance). More on lazy load ads

Scroll Load slots (formerly called Lazy Scroll)

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 Scroll Load Slots for implementation details.

MOAT

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.

Mobile Adhesive Banner

A mobile ad unit that sticks to the bottom of the user's screen as they scroll. Styled by site CSS. More on adhesive banner styling here

Native Advertising

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 our provider for this.

Operative

Our order management system for ads.

Pre-roll advertising

Video ads that runs before video content.

Pubmatic (PMP/UOE)

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.

Remnant

Usually refers to below-the-fold ads that are run-of-network, low-yield. Usually served through AdEx.

RON (Run-of-network)

Ads that run across the entire network of sites.

Segment

Meredith's current analytics vendor.

Selectable Media

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.

Viewability

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.

Wallpaper ads

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.

Show examples in: