Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

Google AdSense for AJAX Content


:P
On this page:

I recently updated my old Support Message Board Web site that previously was purely server rendered to a site that mixes server rendered content with dynamically loaded AJAX content. The app is a message board application, that uses a panel browsing layout. Any directly accessed URLs use server rendering to get content into the page, but any subsequent requests to update messages pulls down just a the actual message content as HTML and then injects that into the document. The result is a much smoother browsing experience.

In the site below the full page renders with server rendered output initially. Any clicks on messages then refreshes the right panel with content downloaded via AJAX and refreshing just the messaging area:

MessageBoardWithAds

The result is a much faster and smoother navigation experience than refreshing the entire page.

AdSense and AJAX

Ok old hat, that's nothing new or exciting really.

But the issue is that Google Adsense ads display just fine when the page is initially server rendered, but are not rendering at all when the right hand panel is updated with AJAX loaded messages. The AJAX loaded content includes the ad markup including script code, but because the markup is loaded dynamically via AJAX it's not properly activated and so no ads actually render with the AJAX content by default.

AdSense by default doesn't officially support AJAX content and some quick searching around seems to confirm that fact. But it looks like there are workarounds one of which I'll discuss here.

The Adsense default script that Google provides for displaying ads looks like this:

<!-- MessageBoard Thread Responsive Ad -->
<script src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js" async ></script>
<ins class="adsbygoogle"
        style="display:block"
        data-ad-client="ca-pub-XXXXXXX"
        data-ad-slot="63623XXXXX"
        data-ad-format="auto"></ins>           
<script>
    (adsbygoogle = window.adsbygoogle || []).push({});
</script>

And this works fine for server rendered ads. You can embed this script into the page and an ad displays. However, when loading this script content via AJAX the script code isn't explicitly fired. While the ad placeholder gets embedded into the page, the script tag doesn't get fired.

Breaking up the Script

But luckily there's a relatively easy way to make this work by breaking up the google script code into its component pieces:

  • Put the script link into the header (so it only loads once – a good idea even for server rendered pages)
  • Put the <ins> tag placeholder whereever it needs to display (also in AJAX content)
  • Call the trigger code on AJAX reloads explicitly

So we'll start by putting the script tag into the header or the bottom of the page. Where doesn't really matter but it needs to be handled as part of the initially rendered page.

<script src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js" async ></script>

Then embed the <ins> tag in the location(s) of the document where it shows. In my case that's in the rendered Message partial where ads are rendered after particular messages (1,3,6):

@{ int msgCount = 0; foreach(var msg in Messages) { msgCount++; <article> <div class="message-body"> ... </div> @if (msgCount == 1 || msgCount == 3 || msgCount == 6) { <!-- script in layout and on bottom and ajax refresh in loadTopicAjax() <!-- MessageBoard Thread Responsive Ad --> <ins class="adsbygoogle" style="display: block" data-ad-client="ca-pub-4571123155768157" data-ad-slot="6111111111111" data-ad-format="auto"></ins> } </article>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
}

Now, the script at the bottom fires on server rendered content and everything works as expected – I get a max 3 ads rendered into my content.

The Google script appears to have some awareness about where it lives in the page, as it renderes 3 ads in the right place in the page. If you move the script to the bottom of the page as I initially tried however, only the first script is rendered. So the script figures out which tag to render based on the location in the page. When run out of context (ie. on the bottom of the page) it appears the script fires only the first embedded ad it can find.

AJAX Loaded Message Content

When messages are reloaded via AJAX when a user clicks a message after the initial page load, the application makes an XHR call to retrieve a partial HTML fragment that contains just the message content without all the 'frame' chrome and extracts just the the content. The downloaded AJAX content is essentially identical to the message body we rendered before minus the message list. The HTML in this payload includes the threaded message along with the embedded Google Adsense ads.

The problem is that when the AJAX HTML is embedded into the page, the script code associated with the Ad markup is not automatically fired.

The work around to make this work is explicitly fire the script code that updates the ad on the page by adding the activation script code to the AJAX callback that merges the content into the page.

Here's the (truncated) client code that reloads messages into the page via the AJAX request:

function loadTopicAjax(href) {        
    $.get(href, function(html) {
        var $html = $(html);

        var title = html.extract("<title>", "</title>");
        window.document.title = title;

        var $content = $html.find(".main-content");
        if ($content.length > 0) {
            html = $content.html();
            $(".main-content").html(html);

            // update the navigation history/url in addressbar
            if (window.history.pushState && !hrefPassed)
                window.history.pushState({ title: '', URL: href }, "", href);

// fire google ads (adsbygoogle = window.adsbygoogle || []).push({}); } else return; }); return false; // don't allow click };

The key item in regards of the AdSense is to trigger the ad display code as part of the AJAX result, so after the message has been loaded and updated we can trigger the Google ad code again and the ad will then be displayed properly.

The key item is:

(adsbygoogle = window.adsbygoogle || []).push({});

which activates the ad.

Good news, bad news

Notice that I said the ad – singular.

While the above code works to trigger an ad via AJAX, it unfortunately only triggers the first ad on the page, not any of the subsequent ones. The issue here is that script code has some internal awareness of where it's running in the page and finding the adjacent <ins> tag to render the ad. If called generically as I'm doing here (either on the bottom of the page in server render, or as above in the AJAX callback code) only the first ad actually renders.

So I'm only able to render a single ad on the AJAX calls, but all three render one server side rendering.

I haven't found a way around this – if anybody knows of a way to make this happen, please leave a comment. I suspect it might be possible with options as part of the push command but I couldn't find any documentation on this.

Careful!

All of this is actually unsupported. Officially Google doesn't support ads in AJAX based content and what I describe here is somewhat unorthodox and based on a hack. It works, but it can easily break if Google decides to change how the script code works.

In my Message Board application I'm not doing anything unorthodox with the ad-units as I'm simply trying to get new ad units to display when AJAX navigation has taken place – ie. new content is loaded. This is really no different than loading a new page and displaying new ads. But Google's policies and terms explicitly forbid tinkering with the ad code and not displaying more than 3 ad units per page. Technically, the code I'm using is violating that – since I have a single page effectively replaces the same page's content with new content. But logically, this is doing what traditionally a full page reload would do, so I'll take my chances in fair use under those terms.

But, it's easy to see how this approach could be used to hijack ads and trigger a lot of ad refreshes on a single page which is where you can easily run into problems with Google's policy. So use this with caution, and be aware that you're skirting the outer realms of Google's Terms of service and you can potentially get cut off for violating their terms. Use at your own risk. Be weary and err on the side of caution. If in doubt, contact Google and ask.

Posted in SEO  HTML  ASP.NET  

The Voices of Reason


 

Jackywest
April 12, 2016

# re: Google AdSense for AJAX Content

Hi,
I've stumble upon your website many times and I noticed that your really skilled and you know what your doing. I just wanted to say thank you for sharing your solution. I've been searching for that kind of solution for quite a long time. And even i've not tried to implement it yet it's really refreshing to see that we're not alone on this problem.
Google not supporting Ajax and SPA website is a joke to me, why the best tech company in the world would not support his own new trending framework ? And more the using of new web technology... It's not like they don't know we exist !
I find it sad for all programmer who had skill and want to make a few bucks. We built internet everyday and we can't use it for leaving, or with hard times. Anyway that was just my feeling on this quest.

Back to the main subject, I've think of this kind of solution, playing with the request and the URL.
So to summup your solution is to change the URL and Title on each change and fire google ads right after ?
Can we do this on one place like "locationChange" ?

$rootScope.$on('$locationChangeStart', function () {

// update the navigation history/url in addressbar
window.history.pushState({ title: '', URL: href }, "", href);

// fire google ads
(adsbygoogle = window.adsbygoogle || []).push({});
});
Something like that ?

Anyway the fact that your using on your own website is trusting me to use it on my own.
I'll start implementing it today.

Thank you again.

Rick Strahl
April 12, 2016

# re: Google AdSense for AJAX Content

@JackyWest - yes for Angular I use similar code like that for Google Analytics and that works fine and that code will work globally if you have ads on the page, but only with the first one.

Nytsee
April 09, 2017

# re: Google AdSense for AJAX Content

Hello everyone !!

No workaround needed in here, google provides a pretty clean solution for web pages Ajax based https://support.google.com/dfp_sb/answer/2694377?hl=en


Dan
May 13, 2017

# re: Google AdSense for AJAX Content

The above answer is not valid for AdSense. It is against the TOS. https://support.google.com/dfp_sb/answer/2694377?hl=en


West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024