SDK Recipes: Advanced Integration

Debug, native ads, and custom rendering patterns

SDK Recipes: Advanced Integration

Advanced integration patterns for debugging, native ads, and custom rendering.


Recipe 8: "I need native/in-feed ads"

Problem: You want ads that blend with your content feed.

Native Ad Implementation

1. Mark element as native slot

<!-- Article feed -->
<div class="feed">
  <article class="article-card">
    <h2>Real article 1</h2>
    <p>Real content...</p>
  </article>

  <!-- Native ad placeholder -->
  <article class="article-card nativeinfeed" data-collapse="1">
    <h2>Placeholder title</h2>
    <p>This content will be replaced by native ad</p>
  </article>

  <article class="article-card">
    <h2>Real article 2</h2>
    <p>Real content...</p>
  </article>
</div>

Key classes:

  • nativeinfeed - Marks element as native ad container
  • data-collapse="1" - Hides element if no ad available

2. Automatic slot detection

With autoslot: 1, the SDK automatically finds .nativeinfeed elements:

dlApi = {
  target: "SITE/AREA",
  autoslot: 1,  // Auto-detects native slots
  async: 1
};

3. Restore content if no ad

When a native slot gets no ad, restore the editorial content:

dlApi.cmd.push(function(dlApi) {
  dlApi.on("afterDestroySlot", function(event, slot) {
    // Check if this was a native slot
    var el = document.getElementById(slot.div);
    if (el && el.classList.contains('nativeinfeed')) {
      // Restore editorial content
      el.innerHTML = `
        <h2>Real article title</h2>
        <p>Real editorial content here...</p>
        <a href="/article-url">Read more</a>
      `;
      // Show the element again
      el.style.display = '';
    }
  });
});

Manual Native Slot Definition

For more control, define native slots manually:

dlApi = {
  target: "SITE/AREA",
  autoslot: 0,  // Manual control
  async: 1,
  cmd: []
};

dlApi.cmd.push(function(dlApi) {
  // Define multiple native slots
  dlApi.defineSlot("infeed1", "native-slot-1", {
    pos: 1,
    native: true
  });

  dlApi.defineSlot("infeed2", "native-slot-2", {
    pos: 2,
    native: true
  });

  dlApi.fetch();
});

Track Native Ad Events

dlApi.cmd.push(function(dlApi) {
  dlApi.on("afterDisplay", function(event, ad) {
    if (ad.native) {
      console.log("Native ad displayed:", ad);
      // Track to analytics
    }
  });

  dlApi.on("empty", function(event, slot) {
    console.log("No native ad for:", slot.name);
    // Restore editorial content
  });
});

SDK Objects Used

  • Native ad classes: nativeinfeed
  • dlApi.defineSlot() - Manual slot definition
  • dlApi.on("afterDestroySlot") - Slot removal event
  • slot with native property

Recipe 9: "I need custom ad rendering"

Problem: You need special ad formats or custom templates.

Custom Template Registration

1. Register your custom renderer

dlApi.cmd.push(function(dlApi) {
  dlApi.registerTemplate({
    // Template identifier (from campaign setup)
    tplCode: "1746213/CustomFormat",

    // Your rendering function
    renderAd: function(ad) {
      console.log("Rendering custom ad:", ad);

      // Create custom HTML structure
      var container = document.createElement("div");
      container.className = "my-custom-ad";

      // Access ad data
      container.innerHTML = `
        <div class="custom-ad-header">
          <span class="sponsor">Sponsored</span>
        </div>
        <div class="custom-ad-body">
          <img src="${ad.fields.image}" alt="${ad.fields.headline}">
          <h3>${ad.fields.headline}</h3>
          <p>${ad.fields.description}</p>
          <a href="${ad.meta.adclick}${ad.fields.url}"
             class="custom-cta"
             target="_blank">
            ${ad.fields.cta || 'Learn More'}
          </a>
        </div>
      `;

      // Insert into slot
      var slotElement = document.getElementById(ad.div);
      slotElement.appendChild(container);

      // IMPORTANT: Track impression
      if (ad.meta.impression) {
        var pixel = new Image();
        pixel.src = ad.meta.impression;
      }

      // Track click properly
      var link = container.querySelector('a');
      link.addEventListener('click', function(e) {
        // ad.meta.adclick already prepended to href
        console.log("Custom ad clicked");
      });
    }
  });
});

2. Ad object structure

The ad parameter contains:

{
  // Ad metadata
  meta: {
    adclick: "https://click-tracking-url/",  // Click tracker prefix
    impression: "https://impression-url/",    // Impression pixel
    adid: "12345",                            // Ad ID
    cmpid: "67890"                            // Campaign ID
  },

  // Creative data (depends on template)
  fields: {
    headline: "Product Title",
    description: "Product description...",
    image: "https://cdn.example.com/image.jpg",
    url: "https://destination-url.com",
    cta: "Shop Now",
    price: "$99.99"
    // ... other custom fields
  },

  // Slot reference
  div: "ad-slot-id",         // Container element ID
  slot: slot,                // Slot instance

  // Template info
  tpl: "1746213/CustomFormat"
}

Multiple Custom Templates

dlApi.cmd.push(function(dlApi) {
  // Product carousel template
  dlApi.registerTemplate({
    tplCode: "1746213/ProductCarousel",
    renderAd: function(ad) {
      // Render carousel with multiple products
      var carousel = createCarousel(ad.fields.products);
      document.getElementById(ad.div).appendChild(carousel);
      trackImpression(ad.meta.impression);
    }
  });

  // Video template
  dlApi.registerTemplate({
    tplCode: "1746213/VideoAd",
    renderAd: function(ad) {
      // Render video player
      var player = createVideoPlayer(ad.fields.videoUrl);
      document.getElementById(ad.div).appendChild(player);
      trackImpression(ad.meta.impression);
    }
  });

  // Interactive template
  dlApi.registerTemplate({
    tplCode: "1746213/Interactive",
    renderAd: function(ad) {
      // Render interactive experience
      var interactive = createInteractive(ad.fields);
      document.getElementById(ad.div).appendChild(interactive);
      trackImpression(ad.meta.impression);
    }
  });
});

Important: Tracking Requirements

Always preserve click and impression tracking:

renderAd: function(ad) {
  // ✓ CORRECT - Impression tracking
  if (ad.meta.impression) {
    var pixel = new Image();
    pixel.src = ad.meta.impression;
  }

  // ✓ CORRECT - Click tracking (prefix preserved)
  var link = document.createElement('a');
  link.href = ad.meta.adclick + ad.fields.url;

  // ✗ WRONG - Missing impression
  // (No tracking pixel)

  // ✗ WRONG - Broken click tracking
  link.href = ad.fields.url;  // Missing adclick prefix!
}

Template with Error Handling

dlApi.cmd.push(function(dlApi) {
  dlApi.registerTemplate({
    tplCode: "1746213/SafeTemplate",
    renderAd: function(ad) {
      try {
        // Validate required fields
        if (!ad.fields.image || !ad.fields.headline) {
          console.error("Missing required fields:", ad);
          return;
        }

        // Render ad
        var container = createAdElement(ad);
        document.getElementById(ad.div).appendChild(container);

        // Track impression
        if (ad.meta.impression) {
          new Image().src = ad.meta.impression;
        }

      } catch (error) {
        console.error("Template render error:", error, ad);
        // Fallback to standard rendering
        ad.renderStandard();
      }
    }
  });
});

Access Ad Instance Methods

The ad object is an ad instance:

renderAd: function(ad) {
  // Access ad methods
  console.log("Ad ID:", ad.adid);
  console.log("Campaign ID:", ad.cmpid);

  // Watch visibility
  var view = ad.watchVisibility();
  view.on('viewed', function() {
    console.log("Custom ad was viewed");
  });

  // Access counter for tracking
  ad.counter.finish();  // Mark ad as loaded
}

SDK Objects Used

  • dlApi.registerTemplate() - Register custom renderer
  • ad object - Ad data with fields and metadata
  • ad.meta - Tracking URLs and metadata
  • ad.fields - Creative field data
  • ad instance - Ad object with methods

Next Steps