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:
<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 configuration 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: '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>
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.
<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 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.
<div id="div-gpt-square-fixed-1" data-tier="1" role="complementary" aria-hidden="true"></div>
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".
karma.config.scrollLoadBatchSize. More about instant/lazy/scroll load slots in the slot catalog.
<div id="div-gpt-square-fixed-1" data-tier="1" data-scroll-load="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. If you want finer control over the timing of the initial ad request, take a look at the window.karma.config.go() method.
For a fully functioning example of a page that has nothing but KARMA ads on it, see example KARMA pages
Specific documentation on the on-page KARMA configuration properties follows.
Some config properties are set by the site. Some are set by KARMA.
window.karma.config.onPageSettings window.karma.config.staticThese 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
<head> config/init snippetwindow.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 */ });
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.
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. We recommend user agent-based detection rather than screen size detection.
window.karma.config = {
isMobile: !!userAgent.match(/Mobi/) && !userAgent.match(/iPad/), /* true on mobile devices, false on non-mobile */
// more properties ...
}
Type: string
If your karma.config.site value begins with ddm. or revshare., this property should be set to 'ddm'.
window.karma.config = {
adUnitFormat: 'ddm'
// more properties ...
}
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.
window.karma.config.site = `ddm.parents.${window.karma.config.isMobile ? 'mob' : 'com'}`;
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:
kw)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 ...
};
Type: string
A string that uniquely identifies the page. This enables us to target ads to a particular page. The id should:
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).
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:
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.
window.karma.config = {
targeting: {
type: 'recipesc',
// more key/values...
}
// more properties...
}
Type: string
If your site is an externally-hosted application, you need to tell us the name of the application.
window.karma.config = {
targeting: {
type: 'other',
'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 |
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. KARMA uses this value to build the ad unit, thus it is required.
window.karma.config = {
targeting: {
channel: 'recipes', /* REQUIRED */
// 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 with the ad request and can be targeted in GAM line items as custom criteria.
window.karma.config = {
targeting: {
foo: 'bar',
// more key/values ...
}
// more properties ...
}
Type: Array
An array containing all the slot types that will be refreshed when user-initiated refresh is triggered via karma.refresh()
karma.config.refresh.userInitiated.slotTypes.indexOf('leaderboard:tier1') > -1
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
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
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
}
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 placeholder codes. Read on to learn 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 placeholder you need 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.cmd.push(function(){
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. More details on tiers here.
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.
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. window.karma.cmd.push().window.karma, apart from configuration values discussed above. KARMA relies on globally scoped variables in order to do its thing.role="complementary" and aria-hidden="true" attributes.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:
| 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="div-gpt-leaderboard-flex-1"data-tier="1"data-scroll-load="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>
<!-- 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>
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. 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 |
Note: Additional site CSS is required for the mobile adhesive banner.
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 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>
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>
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.
| 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 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
. |
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);
});
});
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();
});
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 |
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');
});
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.
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();
});
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 |
window.karma.getSlotById('div-gpt-leaderboard-flex-1'); //returns the slot object.
Get the total number of ad slots on this page. Returns an integer.
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.');
});
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. |
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)
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
) |
window.karma.report('CollapseCode', 1234567890);
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? |
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
);
});
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 |
// Clear page targeting
karma.clearTargeting('foo')
// Clear slot targeting
karma.clearTargeting('foo', karma.getSlotById('div-gpt-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 |
permanent |
boolean | If true, disables refresh on the slot permanently, set to true. Leave this undefined to allow re-enabling via
karma.reEnableTimedRefrehOnSlot |
// 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');
Re-enabled timed refresh on a given slot.
karma.reEnableTimedRefreshOnSlot(slotId)
| argument | type | description |
|---|---|---|
slotId |
string | required - the DOM id of the ad slot |
// re-enable timed refresh on a slot
window.karma.reEnableTimedRefreshOnSlot('div-gpt-square-fixed-1');
Restart leaderboard docking if it has been previously released.
// restart leaderboard docking
window.karma.initDocking();
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' |
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');
});
Re-inititalizes rail docking. Commonly used on auto-advance. For more details, see our rail docking documentation
window.karma.rebuildRails();
Triggers a user-initiated refresh (e.g. when a user clicks to the next slide in a slideshow).
window.karma.config.refresh.userInitiated.slotTypes.window.karma.slots.refreshkarma.refresh(slotsToRefresh)
| argument | type | description |
|---|---|---|
slotsToRefresh |
array | optional
- a list of slot ids to refresh. Defaults to
karma.slots.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',
]);
});
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 |
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);
});
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()).
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!');
}
}
});
}
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.
<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>
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.
// clear previous bid information
window.karma.resetVideoTargeting();
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.
// request new bids and store targeting
window.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 event 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 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.
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');
});
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
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.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 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:
Should the banner roll back up after a specified time?
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.
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
Rails on Grid Layouts
<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>
If your page has a grid layout...
Besides the 2 required configurable classes:
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.
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 a docked leaderboard or rail, use the releaseDocking API method.
window.karma.releaseDocking('leaderboard');
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
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)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 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.
These are standalone pages that have nothing but KARMA on them.
KARMA 3
Universal KARMA:
Site-specific KARMA (aka Element):
What to do when you suspect an ad is misbehaving:
The handy-dandy KARMA bookmarklet:
The bookmarklet is compatible with Chrome (desktop and mobile), Firefox, Safari (desktop and mobile), and Edge.
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.
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
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.

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.

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.

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.

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).
// 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 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 |
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 |
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 |
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 |
Amazon's header bidding framework.
A vendor/platform for building rich media ads for mobile (sort of like Flash is used for desktop).
Click-through rate. The percentage of ads that get clicked on.
Campaign Manager.
Client Services Manager
Cost per click.
Cost per million impressions.
Google Ad Manager. The software that our ad operations team uses to manage the ads that get served into the GPT ad tags.
bhg.mdp.com/tier1/article/gardening)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 Node.js-based custom platform that powers many of our sites.
Google's Header Bidding product
Blocking and viewability technology. Some agencies wrap their ad creative with it.
Google Publisher Tags. The ad framework provided by Google that KARMA uses to serve desktop and mobile ads.
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.
A header bidding vendor that is run through Prebid.
Slots that are included in the HTML markup and requested instantly as the page loads. More on instant slots
The Meredith-developed and maintained Javascript wrapper for GPT.
Slots that are dynamically created/injected into the page based on a user interaction (opening a modal, for instance). More on lazy load ads
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.
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 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
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.
Our order management system for ads.
Video ads that runs before video content.
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 below-the-fold ads that are run-of-network, low-yield. Usually served through AdEx.
Ads that run across the entire network of sites.
Meredith's current analytics vendor.
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.
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.