Native Teasers: Batched In-Feed Ads

Fetch several native teasers in one batch and render them as entries in your content feed with dlApi.fetchNativeTeasers

Native Teasers: Batched In-Feed Ads

dlApi.fetchNativeTeasers fetches native ads for several consecutive feed positions in a single batch and returns them in your content-feed contract shape, so you can inject them into a feed alongside editorial entries.

This method does not render anything into the page. It hands you the data and leaves rendering, feed injection, and event tracking to the page:

  • teasers — an array with one feed entry per filled position, ready to merge into your feed. Each entry carries a bidPos field so you can pair it back to its bids item for tracking.
  • bids — the raw ad data per position. You reach an entry's adm here (via bidPos) and pass it to dlApi.registerBidResponse for impression and viewability tracking.

Use it when the page owns the rendering (for example a homepage feed built server-side or in a framework) and you only need the ad payload in a shape that matches your existing feed entries.

Live Demo

See it working: Content Commerce Teasers Demo

The demo fetches live teasers from the ad server and renders them as feed entries. View the source to see the full fetchNativeTeasersregisterBidResponse flow.

Integration

Step 1: Fetch the teasers

dlApi.cmd.push(function(dlApi) {
  dlApi.fetchNativeTeasers({
    slot: 'flat-natleft3',
    limit: 3,
    opts: { DX_keyword: 'value' }
  }).then(function(result) {
    var teasers = result.teasers; // [entry, entry, ...]
    var bids = result.bids;       // [{ pos, div, adm }]
    // ... Steps 2 and 3
  });
});

slot is required — the promise rejects when it is missing. Teaser campaigns are targeted through the slot and the per-position opts; the SDK does not add any page-wide keyword or key-value of its own.

Step 2: Inject the entries into your feed

teasers contains one entry per filled position, already mapped to the feed contract. Merge them into your feed and render them the same way you render editorial entries. Render each teaser into a container you can locate again in Step 3 — for example an element id derived from the entry's uuid:

myFeed.entries = myFeed.entries.concat(teasers);
renderFeed(myFeed);

Empty positions are excluded from teasers (see Empty Positions).

Step 3: Track impressions, viewability, and clicks

Track from the same teasers list you rendered — not from bids. For each entry, find its bid by bidPos and register the bid's adm on the container you rendered the entry into. This fires the impression and, when the creative is eligible, sets up viewability (Active View) tracking:

teasers.forEach(function(entry) {
  var bid = bids.find(function(b) { return b.pos === entry.bidPos; });
  var container = document.getElementById('feed-entry-' + entry.uuid); // the element you rendered this entry into
  dlApi.registerBidResponse(bid.adm, container);
});

Viewability is only set up when a container element is provided and the creative is marked viewable (adserver_meta.viewability === true). Without a container the impression still fires, but Active View is skipped.

Clicks are not covered by registerBidResponse — you count them through the tile's own link. Set the tile's anchor href to link.href: whenever the ad carries a click-count endpoint, the SDK has already assembled it into the ready-made click-counting URL (meta.adclick + destination), so the browser navigates through the ad server's click-count endpoint, which counts the click and 302-redirects to the real destination. When there is no click-count endpoint, link.href is simply the plain destination.

teasers.forEach(function(entry) {
  tileLink.setAttribute('href', entry.link.href); // the anchor of the tile you rendered this entry into
});

Options

OptionTypeDefaultDescription
slotstring– (required)Slot name used for every position.
limitnumber1Number of teaser positions to fetch (pos 1..limit).
optsobjectTargeting options merged into each position's opts. The SDK adds pos per position.

Return Value

The promise resolves with { teasers, bids } — the entries you render, and the ad data you track.

teasers

One entry per filled position, in order, each matching your feed entry contract and populated from the teaser creative:

FieldDescription
bidPosThe 1..limit position this entry was resolved for. Use bidPos to pair the entry with its bids item (bids.find(function(b) { return b.pos === entry.bidPos; })) to reach the raw adm for registerBidResponse (impression and viewability).
uuidEntry identifier — carries the ad id.
type.codeStory kind for the renderer; defaults to article.
title.textTeaser headline.
title.prefix / title.labelCommercial disclosure markers (for example materiał promocyjny / sponsoring), always set so the tile renders as sponsored content.
image.urlTeaser image URL.
image.sizeCreative dimensions; 0 when the creative carries none.
link.hrefThe tile's single link — set it as the anchor href (see Step 3). Whenever the ad carries a click-count endpoint, this is the ready-made click-counting URL (meta.adclick + destination) so the click is counted by the redirect; otherwise it's the plain destination URL.
summary.textLead text with HTML stripped; present only when the teaser has a lead.
sourcesPartner logo; present only when the teaser carries one.
flagsMarks the entry as content_commerce.
published / modifiedPublication timestamps.
variantsIntentionally absent — the winning teaser variant is already resolved into title / summary, so there is nothing left for the page to choose.

bids

One item per requested position, in order — empty positions included, so the array is always limit long:

[
  { pos: 1, div: 'nativeTeaser_1_ab12cd34', adm: { /* ad data */ } },
  { pos: 2, div: 'nativeTeaser_2_ef56gh78', adm: null } // empty position
]
FieldDescription
posTeaser position, 1..limit — the same value the ad was requested with as pos targeting.
divInternal id of the technical container the SDK used for that position.
admRaw ad data (fields, meta, gctx, lctx) for registerBidResponse, or null when there was no ad for that position.

Empty Positions

When a position returns no ad (or fails), its bid is { pos, div, adm: null } and it is excluded from teasers. If fewer ads come back than requested, teasers is simply shorter than limit.

Because teasers is filtered, its array index no longer matches the requested position. Each entry's bidPos carries its original 1..limit position, so you can still map a surviving teaser back to the right feed slot or bids item.

The consumer decides how to fill the gap — for example by falling back to an editorial entry for that position. The SDK only signals the gap via adm: null.

SDK Methods Used

  • dlApi.fetchNativeTeasers() — fetch the batch, get { teasers, bids }
  • dlApi.registerBidResponse() — count impression and set up viewability per rendered teaser