How To: Loading ads in a Drupal AJAX call asynchronously

How To: Loading ads in a Drupal AJAX call asynchronously

By Boris Baldinger 11th February 2013 Drupal

While working on LikeMag, one of our most recent releases, we were confronted with a challenge: loading ads during a Drupal AJAX (Asynchronous JavaScript and XML) call. This is how we solved it.

The issue

By definition synchronously loaded JavaScript can only add objects like files, content or ads to a page's structure until it is entirely rendered. An additional complexity that can occur while working with third-party advertising providers is that you can not control the performance of their infrastructure. Which means either you accept this risk or try finding a way to mitigate it. We went for the latter.

At this point it is important to stress that it is common practice for third party ads to use the document.write method which only works for the synchronous loading approach. To learn more about the synchronous and asynchronous loading of remote tags I suggest you read the article "synchronous vs. asynchronous tags - what’s the big deal?" on the krux blog. In our case however it became apparent that our solution had to include the asynchronous approach.

While researching possible solutions I found the following tools:

The issue with the the majority of them were, that active development or support wasn't visible, except for PostScribe. This solution offers the following features:

"Krux PostScribe enables the type of tag execution required by most ad formats in an easy-to-use-and-deploy format. It leverages innerHTML to ensure reliable, fast ad delivery."

"Unlike other innerHTML-based solutions (e.g., writeCapture, ControlJS, and OpenTag), Krux PostScribe seamlessly enables the “immediate writes” upon which most ad formats depend."

Which in plain English enables the quick rendering of the page to the user and allowing the ads to respond in their own time without reducing the user's experience.

How to use PostScribe

Download PostScribe directly from its github repository.

Include these files in your project:


Here is a small example:

<div id="myAd"></div>
<script type="text/javascript">
  $(function() {
    postscribe('#myAd', '<script src="remote.js"><\script>');

Our use case

As mentioned in the introduction this solution stems from LikeMag which, besides utilizing PostScribe, is a responsive website and uses the Isotope library to arrange items over the screen automatically depending on the viewport.

Since there are no free lunches on the web, LikeMag has to monetize too and one of their models is built around ads. So in order to deliver the perfect balance between content and ads for every viewport, we had to find a way to render the perfect amount after the identification. And that is moment the where PostScribe comes into play.

Instead of injecting the ads right into the Drupal view and slowing down the loading of the rest of the page, we just print the standard items. In a next step the system iterates over the items and adds the appropriate amount of ad containers to the content with jQuery. (These containers can be addressed with PostScribe, because PostScribe works best when the DOM is ready.) Ad

"But where is the AJAX you mentioned in the title?", I hear you cry. So let's talk about it right now. When we scroll down on LikeMag, which besides being responsive is a smart infinite scroll site too, new items will be loaded through an AJAX call. So here we can use PostScribe as we did before. The only thing that we have to check, is that we do not add ads to already "adified" content. In our case we can check if the view-item was already processed by Isotope.

Code from View, partially modified by isotope and postscribe

See the code as an example:

Drupal.behaviors.ViewsLoadMore = { attach: function(context, settings){
      if ($(context).hasClass('view')) {
        $isotope = $('.view-id-articles .view-content');
        $isotope.isotope('insert', $('.view-id-articles .view-content .views-row:not(.isotope-item)'), function(){
      } else if ($(context).find("html").length == 1){
        // If it contains html, it is the first behavior call.
loadads: function(){      $('.view-articles .views-row.views-row-ad').once('postscribe',function(){
        if(typeof(cachebuster) == "undefined"){var cachebuster = Math.floor(Math.random()*10000000000)}
        if(typeof(dcopt) == "undefined"){var dcopt = "dcopt=ist;"} else {var dcopt = ""}
        if(typeof(tile) == "undefined"){var tile = 1} else {tile++}
        var string = '<scr'+'ipt src=";' + dcopt + ';tile=' + tile + ';sz=300x250;ord=' + cachebuster + '?"></scr'+'ipt>';
        postscribe($(this), string);

As you can see we process only the newly loaded items from the Drupal view and exclude the already processed items.

With this solution we are very flexible to deliver the page content as fast as we can while not depending on the speed of an ad-provider.

Stay in touch – join our newsletter!




Miguel Trindade's picture
Miguel Trindade

Thank you. Very useful.

Bleen's picture

Interesting case study ... I have been battling similar issues in the DART module issue queue ( Writecapture has been the solution there thusfar.

In general though, the biggest challenge on this issue has been figuring out how to handle ads in a responsive world. Without using js to rearrange items depending on the viewport (the way you are doing on likemag) so we have been toying with the breakpoint_context module. Unfortunately the ads do not reload if the viewport changes (ex: the user switches their iphone from landscape to portrait) which is important if you have have 728x90 ads that need to switch to something smaller. It doesnt look like has this issue though...

With your method, how do you handle pageviews/ad impressions in terms of reporting though? With an infinitely scrolling site that seems to be problematic? Even more so if the ads needed to swap out because of size considerations.

Anyway, interesting read... thanks

daniel truninger's picture
Daniel Truninger


You are spot on with your conclusion that our method can react to the viewport changes.

Regarding your questions. We can assure you that our solution also addresses these issues. They will be the subject of a future blog post. Watch this space.

Add comment

Search form

Latest comments