A common question that I find myself fielding lately is how to handle the problem of rotating JavaScript based advertisements. As AJAX becomes ubiquitous on ad supported sites, we must take care that decreasing page views don’t also mean proportionally decreasing revenues.

Many find their way to ScriptManager.RegisterStartupScript, use that to re-inject the script during a partial postback, and expect that doing so will refresh the ad. Unfortunately, that doesn’t work when dealing with JavaScript based ads such as Google’s AdSense.

In this post, I’m going to show you why RegisterStartupScript does not solve the problem, the alternative that I suggest, and how to use that method to also defer loading of advertisements until after your content.


How JavaScript ads are displayed

After being spoiled by high level libraries like ASP.NET AJAX and jQuery, it’s easy to forget how tedious it is to write cross-browser DOM manipulation code. If you do manage to write something from scratch that works well, you’ll usually find that it ends up being quite large.

For this reason, advertising units embedded via JavaScript includes usually use a series of document.write statements to output raw HTML.

For example, I added the Lake Quincy ad in my sidebar with this JavaScript:

Depending on which advertisement is returned from Lake Quincy’s server, s.js will use document.write to eventually render something like:

This HTML renders in the same location that the <script> element is placed.

Google AdSense, Amazon Widgets, and just about every other advertising service that I’ve encountered all use this document.write method.

Why doesn’t RegisterStartupScript work?

There are two reasons why this document.write method makes rotation difficult when using ASP.NET AJAX’s server-side JavaScript methods.

First, the ScriptManager’s RegisterStartupScript method does not allow control over positioning the JavaScript it emits. Since these JavaScript based ads literally dump HTML code right where they are located, being unable to target them is a big problem.

You can attempt to circumvent this with absolute CSS positioning, but it adds a lot of unnecessary complexity to what should otherwise be simple.

Second, most browsers ignore document.write statements after the initial page layout has completed. Even if you found a way to get the script asynchronously injected at the precise location you desire, it would do absolutely nothing in most browsers.

Between these two problems, it becomes apparent that we need to find something altogether different.

So, what does work?

The answer to this dilemma is simple: the iframe.

One very useful property of the iframe is that its contents are created within the scope of a completely new DOM. For our purposes, the benefit of this is that it provides a way to execute document.write statements at any time after the initial page rendering.

Additionally, iframes are as easily positioned as a <div> and the separate DOM protects against unruly ad content breaking out of its intended location.

Encapsulating the ad within an iframe

To move the ad into an iframe, first we need to move the script blocks to an external HTML file. I called this one LQ-336×280.html. This naming scheme helps me keep track of which file corresponds to each advertiser and unit size:

The one thing in that HTML you might not be familiar with is the meta tag. That particular tag instructs search engine spiders to completely ignore the file. It’s my understanding that it’s important to include this to avoid running afoul of Google’s policies, in the same vein as using nofollow on paid links.

Finally, we just have to replace the inline script blocks with an iframe referencing the HTML include file we just created:

The ad is now encapsulated within the iframe, with its own DOM.

Using that iframe to rotate the ad content

Now that we’ve got the document.write code into an iframe, cycling the ad content is as simple as reloading the iframe. This can be accomplished by re-setting its src attribute:

This code allows us to rotate the advertisement at any arbitrary time, independent of the main page’s loading and rendering.

Using this during ASP.NET AJAX partial postbacks

Having figured out a fundamental method for accomplishing the rotation, now we can get back to the original question of how to rotate ads during an UpdatePanel’s async postback.

For example, let’s say that we want to rotate ads during every partial postback. After all, that’s how often they would’ve changed had there been no UpdatePanel.

The easiest way is to handle the PageRequestManager’s EndRequest event:

Optionally, you could perform the rotation at BeginRequest instead. I’ve found that ads receive a slight boost in their CTR when rotated before the request completes, instead of after. It depends on what behavior you want to optimize, engagement or CTR.

Bonus: Deferred loading

Because inline script elements block rendering until they’ve finished downloading and executing, a few slow ad servers may have a tremendous impact on your site’s overall performance.

Now that we’ve gained the ability to render our advertisement anytime we want to, another handy use for this is to defer loading of the ad.

To implement deferred loading, we need to first revise the iframe element in our main page to omit the src attribute:

Then, dynamically set the attribute later in the page load. For example, you could set it inside the Application.Init handler that we created earlier, revising it to:

Now, the page will load completely before the ad’s JavaScript include is evaluated. Depending on the layout of your page, this can dramatically decrease the perceived page load time.

Conclusion

Do apply this technique ethically. Just because you can rotate ads as you desire, that doesn’t mean you should. For instance, if you cycle CPM ads as a result of trivial operations that wouldn’t previously have resulted in an impression, you’ll be cheating your advertisers.

If you’d like to see this in action, just take a look at the source for my sidebar ad. It’s implemented exactly as shown above, to take advantage of deferred loading.

The iframe does have a couple small disadvantages, but I think their flexibility far outweighs any drawbacks. What do you think?