Complete Asynchronous ad loading using DFP and LABjs

March 3rd, 2011 | by Sajal Kayan |

UPDATE: The hack is now available on GitHub.

8th May 2011: This seems to be having problems, will investigate and update when i have time. Pls revert to normal DFP tags for now.

One of the biggest challenges when optimizing performance of websites is third party content – specifically advertisements.

Most ad networks and servers use evil document.write() in their JavaScript(and even nested document.writes) which block further rendering of the page until their code has completed execution. In this blogpost, I’ll show how you can use DFP’s iframe tagging(read warnings there) combined with LABjs and little bit of JavaScript hackery to make any ad load asynchronously with negligible impact on rest of the pageload.

Attention Deficit Disorder version : BeforeAfter

NOTE: Use the method below entirely at your own risk! Use only if you know what you are doing…

Current blocking method

DFP has an experimental method to load ads called iframe tagging. The JS looks like this :-

The Bootstrap: In <head> (Does not have to be in <head> but before the first GA_googleFillSlotWithSize call) :-

<script type='text/javascript' src='http://partner.googleadservices.com/gampad/google_service.js'>
</script>
<script type='text/javascript'>
GS_googleAddAdSenseService("ca-pub-7046344781760701");
GS_googleEnableAllServices();
</script>
<script type='text/javascript'>
GA_googleUseIframeRendering();
</script>

Then wherever we want the ads to display, we put something like this :-

<script type='text/javascript'>
GA_googleFillSlotWithSize("ca-pub-7046344781760701", "test_async_lb", 728, 90);
</script>

With this method, the bootstrap does some blocking. First it loads a JavaScript then the following functions document.write another <script> tag which must load sequentially again. The GA_googleFillSlotWithSize function is relatively inexpensive. All it seems to do is document.write an iframe with various targeting information as parameters in the URL and does not block further rendering. The advantage of iframe tagging is that slow ad networks don’t fuck up your page. But the bootstrap is very expensive as shown in this waterfall chart.

This is what it looks like.

normal DFP iframe bootstrap

The hack

Last few days, I’ve been playing a little with LABjs, specifically its complete async loader.

After playing with LABjs, ive come up with the following LABjs snippet :-

      // intercepts the script inserted via document.write and loads it via LABjs
      function docwrt(str){
        var script = str.replace(/(.*)\=\"/g, '').replace(/\"(.*)/g, '');
        $LAB.script(script).wait(function(){
          GA_googleUseIframeRendering();
          // following function makes the magic happen!
          function Wrapper_googleFillSlotWithSize(pubid, slotname, width, height, target){
            var docwrttemp = function(str){
              target = document.getElementById(target);
              target.innerHTML = str;
            };
            document.write = docwrttemp;
            GA_googleFillSlotWithSize(pubid, slotname, width, height);
          }
          // usage of the new wrapper here "leaderboard" and "skyscraper" are target div ids
          Wrapper_googleFillSlotWithSize("ca-pub-7046344781760701", "test_async_lb", 728, 90, "leaderboard");
          Wrapper_googleFillSlotWithSize("ca-pub-7046344781760701", "test_async_sky", 160, 600, "skyscraper");
        });
      }

      document.write = docwrt; //intercepts document.write from below script
      $LAB.script("http://partner.googleadservices.com/gampad/google_service.js").wait(function(){
        GS_googleAddAdSenseService("ca-pub-7046344781760701");
        GS_googleEnableAllServices();
      });

(note: Since I’m lazy, I haven’t restored document.write back to its original glory.)

Here Wrapper_googleFillSlotWithSize is a wrapper around GA_googleFillSlotWithSize which takes a 5th argument – target – This is the id of <div> where we want to show the ad.

Here is a sample page using this hack. Id appreciate it if I get some feedback about this method via comments below. As I said earlier, use your own better judgment before using this snippet in production. I welcome criticism but will not accept blame if this doesn’t work for you.

In my simple example, it may seem it takes longer to fully load the page, but if you have many other things on the page, the overall effect will be better with this hack. Moreover, if you are already using LABjs on your site, this is a no-brainer. With this method, even if Google is inaccessible(for whatever reasons) it wont SPOF your page.

Slow motion video of pageloads on IE8:-


Generated via webpagetest.org

Left is normal method, right is hacked version.

Currently tested on IE(7 thru 9), Firefox 3.6.11, Chrome 10.0.648.45 dev and an unknown version of Safari.

Conclusions…

The world would be a much better place without the evil document.write(). Google should know better. They should make a function like Wrapper_googleFillSlotWithSize by default.

  • http://www.sajalkayan.com/optimizing-dfp-performance.html Sajal Kayan » Optimizing DFP performance

    [...] UPDATE: I am now using Aaron’s adsense hack to defer DFP below the content. Thanks Aaron UPDATE 2: New Post: Complete Asynchronous ad loading using DFP and LABjs [...]

  • http://getcreditable.com Ryan

    Thanks for building this! It seems to be working fine. I am, however, getting an error in Chrome: Uncaught SyntaxError: Unexpected token < – Access Denied

    Doesn’t seem to affect the ad loading, but any idea what is going on?

    Thanks again!

  • http://www.sajalkayan.com Sajal Kayan

    @Ryan : Which url do you get the error on? I tried both the before and after links which show no error on chrome.

    Also at https://github.com/sajal/async-DFP-ads ive fixed a bug which pertains to the cookie setting function which is called if no cookies are set.

  • http://getcreditable.com Ryan

    My bad! Wrong url for your script

  • http://getcreditable.com Ryan

    Thanks Sajal – I downloaded the new version on Github — works like a charm. Thanks again for writing this. My page loads were getting hung up because my ads are at the top of the page and I was considering dropping DFP altogether.

    -Ryan

  • http://www.supdadupawebdesign.co.uk David

    Do you know if its possible to run this on the non-iframe style code?

  • http://www.sajalkayan.com Sajal Kayan

    @David: Nopes, it doesnt work on non-iframe version.. I was trying to get it to work, but its just too complex for me.

  • Steele

    I tried this on my site, works fine.

    One problem – most ad networks can display a ‘default tag’ instead of an ad, in case they don’t have 100% fill rate on our inventory (which most networks don’t).

    Can this be done somehow? Basically they would need to write a DIV on the page (e.g. ), but this would be done asynchronously through DFP *after* the page loads. In which case this div might not be filled with our fall-back default ad (say Adsense).

  • http://www.sajalkayan.com Sajal Kayan

    @Steele : Well, DFP will work exactly as its supposed to….

    Note that i use DFP’s iframe method ( http://www.google.com/support/dfp_sb/bin/answer.py?hl=en&answer=90777 )

    So everything happens inside of an iframe which google creates…. ive been using this method with adsense backfil without any issues. Let me know if you have any other concerns.

  • Steele

    Thanks Sajal. I Sorry, should have been more clear – what I mean is – is it possible to use another DFP tag as a backfill?

    Let’s say I have a target div where I display ads from various networks (Priority_300x250):
    Wrapper_googleFillSlotWithSize(“ca-pub-XXX”, “Priority_300x250″, 300, 250, “SLOT_300x250″);

    Now say ValueClick can’t fill the spot, and as a backfill, I want them to execute another DFP tag in it instead (Backfill_300x250):

    Wrapper_googleFillSlotWithSize(“ca-pub-XXX”, “Backfill_300x250″, 300, 250, “SLOT_300x250″);

    That way I control what I run as backfill, not just Adsense, but I can add/remove/edit any other networks/campaigns from that backfill slot.

    I guess I would have to place the Wrapper_googleFillSlotWithSize function in the page header. But even then, would it work?

  • http://www.sajalkayan.com Sajal Kayan

    @Steele : I think what you describe can’t be done with DFP’s iframe implementation. If it can be done, please point me to their docs and ill update the hack…

    Since ads run in an iframe, you can put in regular DFP tags as the value click default ad, but im not sure if the adsense targeting will be correct or not.

  • http://www.sajalkayan.com Sajal Kayan

    This seems to be having problems, will investigate and update when i have time. Pls revert to normal DFP tags for now.

    Since a few mins ago, im seeing strange behaviour. with this hack in place many slots were not being filled. without it it fills as usual. Im extremely busy this week, will investigate later.

  • http://www.semlerresearch.com Bioequivalence

    Thanks for your great effort.. You will correct that error and update that.. WE will wait for that..

  • http://www.facebook.com/people/Kevin-Watt/573096952 Kevin Watt

    Is the newer version working better?  Thanks!

  • http://www.cashmoustache.com Skywalk3r

    Hi,

    i think i’ve found something that could solve the problem of deferring the loading of DFP ads. I just wrote something about that here : 

    http://www.cashmoustache.com/post/11136289258/how-to-make-a-late-asynchronous-call-of-dfp-ads

    I don’t know if it is a known solution but i didn’t read it elsewhere.
    By the way, i’m sorry if my english is not good.
    Tell me if you think that’s usable. I’m testing it on the website which i’m working for since yesterday and it seems to run very well.

  • Anonymous

    excellent. i didn’t know about GA_googleUseFriendlyIframeRendering();

    Looks interesting…. i wonder if it works with third party ads as well… ones that have a document.write in them.

    PS: when using GA_googleUseIframeRendering();  you dont need GA_googleAddSlot … so i guess in your method as well thats not needed.

  • Skywalk3r

    I don’t think there is a limitation in the content type (most of the ads we display on the website i work for are 3rd party ads and i have not noticed any problem with ads containing document.write() calls.)

    I just checked and indeed GA_googleAddSlot() is not needed (thanks). I also noticed that GS_googleEnableAllServices() and GA_googleUseFriendlyIframeRendering() can’t be in the same tag. I don’t know why but i updated my post in regard of both these info.

  • http://www.sajalkayan.com/dfp-now-officially-supports-asynchronous-rendering.html Sajal Kayan » DFP now officially supports asynchronous rendering!

    [...] DFP launched asynchronous ad loading. For the past few months ive been trying to load ads in a manner where it doesn’t affect rest of the page load, this new development [...]

  • http://www.incrediblogger.net/ Make Money Online

    Hi Sajal,
    Now that we have the google asynchronous ad loading is this method still required?

  • http://www.bloggingshiksha.com/2011/09/google-adsense-guide-perfect-director-for-adsense-publisher/ adsense guide

    hi,

    Sajal i would thank you for Sharing the code online…

blog comments powered by Disqus