Welcome to WebmasterWorld Guest from 50.19.34.255

Forum Moderators: incrediBILL & martinibuster

Infinite Scroll with Adsense (finished code, open to improvements)

     
1:52 am on May 25, 2017 (gmt 0)

Preferred Member

Top Contributors Of The Month

joined:Mar 15, 2013
posts: 570
votes: 47


Well, guys, I have the Infinite Scroll feature working, and I have Adsense working with it! It's taken me a solid month to get it going, and I've had very little input from anyone on here, the Google support forum, or my Google rep, so I'm getting the feeling that very few people have gotten this far with it.

Or if they have, they're keeping it a secret.

So, for the sake of helping out future coders, I'm gonna share everything I have. If you guys can offer any improvement suggestions, great! If not, maybe someone in the future will come across them and save a month of work.

Step 1: Preparing Infinite Scroll
I'm using jQuery to get the Infinite Scroll section working, mainly because it uses the Ajax response fragment (.load()). There may be a way to do it without jQuery, but I was already using it so it didn't matter.

So first, load jQuery in the header:

<script src="//code.jquery.com/jquery-2.2.4.min.js"></script>

(There are newer versions, but this is the version that gave me the least problems.)

Next, I'm using the jQuery plugin ScrollMagic, so load it after jQuery:

<script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.5/ScrollMagic.min.js"></script>


Step 2: Preparing Adsense
As of the time that I'm writing this, you CAN'T just use Adsense in an Infinite Scroll. The only way to do it is by moving over to DFP, which is a HUGE pain, but necessary.

If you haven't already done so, set up your account here:

[google.com...]

It should automatically link to your Adsense account. Click on "Inventory" and create the new ad tags that you want to use.

Once you've created them, add this to your header (I did it after the ScrollMagic plugin, but you can probably do it anywhere in the header), following the notes in the script:

<script async src="https://www.googletagservices.com/tag/js/gpt.js"></script>

<script>
var googletag = googletag || {};
googletag.cmd = googletag.cmd || [];

// REQUIRED: slot[] will be used to assign each tag
var slot = new Array();

// OPTIONAL: Define Responsive Tags
// I'm using these to define DFP's version of responsive banners. They're not
// exactly the same, though; instead of showing the ad that pays the best, they
// just show the first one that fits the width of the section provided. DFP doesn't
// support true responsive banners at this time
var horizontal_ad, footer_ad;

googletag.cmd.push(function() {

// OPTIONAL: if you defined responsive tags above
// Set size mapping; you can add as many addSize() tags as you need
horizontal_ad = googletag.sizeMapping().
// shows a 728x90 on a width > 728x0
addSize([728, 0], [728, 90]).

// else, shows a 320x50 on a width > 320x0
addSize([320, 0], [320, 50]).

build();

// Another example, without the notes
footer_ad = googletag.sizeMapping().
addSize([728, 0], [728, 90]).
addSize([320, 0], [300, 250]).
build();

// OPTIONAL: slot[0], slot[1], and slot[2] are for banners that are not used in
// the Infinite Scroll, so I define them manually. You can make as many as you
// want, just increment the array number for each one
//
// The /xxxx/Horizontal_Banner comes from DFP. You can generate a tag to
// find them if necessary
slot[0] = googletag.defineSlot('/xxxx/Responsive_Horizontal_Banner',

// 728x90 and 320x50 means that I have 2 sizes to choose from. It will try
// the 728x90 first, and if it doesn't fit it tries the 320x50
[[728, 90], [320, 50]],

// This is the ID of the DIV tag where the ad will go
'banner_0').

// OPTIONAL: If you defined horizontal_ad was defined above with .sizeMapping()
defineSizeMapping(horizontal_ad).

// This is necessary to load the banner
addService(googletag.pubads());

// Another responsive example, without the notes
slot[1] = googletag.defineSlot('/xxxx/Responsive_Footer',
[[728, 90], [300, 250]], 'banner_1').
defineSizeMapping(footer_ad).
addService(googletag.pubads());

// This is a sample of a non-responsive banner, not used in the Infinite Scroll
slot[2] = googletag.defineSlot('/xxxx/Medium_Rectangle',
[300, 250], 'banner_2').
addService(googletag.pubads());

// REQUIRED
googletag.pubads().enableSingleRequest();
googletag.pubads().disableInitialLoad();

// OPTIONAL: this will force ad DIVs to hide if there's not an ad available
// googletag.pubads().collapseEmptyDivs();

// REQUIRED
googletag.enableServices();
});
</script>


Step 3: Placing Ads Outside of Infinite Scroll

This is the easy part. You've already defined everything for this in the header, so you can place these wherever you want:

// This corresponds with the slot[0] that's defined in the header
<div id="banner_0">
<script>
googletag.cmd.push(function() {
googletag.display('banner_0');
googletag.pubads().refresh([slot[0]]);
});
</script>
</div>


Step 4: Adding functions for Infinite Scroll

This uses jQuery, but could probably be modified to not use it. I put these in a separate javascript.js:

function scroll() {
scroll.controller = new ScrollMagic.Controller();

if (scroll.startLoad && scroll.padding)
$(scroll.startLoad).css({'position': 'relative', 'top': '-' + scroll.padding + 'px'});

else scroll.startLoad = scroll.loadingID;

scroll.scene = new ScrollMagic.Scene({triggerElement: scroll.startLoad, triggerHook: 'onEnter'})
.addTo(scroll.controller)
.on('enter', function(e) {
if (!$(scroll.loadingID).hasClass('active')) {
$(scroll.loadingID).addClass('active');

setTimeout(loadMore(), 1000);
}
});
}

function loadMore() {
$(scroll.listID).append($('<div></div>')
.load($(scroll.nextClass + ':last').attr('href') + ' ' + scroll.itemID, function() {

// This is optional, really, but I used the variable for my own purposes
if (!scroll.increment) scroll.increment = 1;
scroll.startCount += scroll.increment;

if (typeof(window[scroll.callback]) === 'function')
window[scroll.callback](scroll.startCount);
})
);

scroll.scene.update();
$(scroll.loadingID).removeClass('active');
}


Step 5: Using Infinite Scroll

In the section that you want to scroll, you'll need a parent container and a child container. The parent container is what will be appended to, and the child is what will be loaded and appended by.

I'm using PHP, and before the HTML I use this to set the starting and ending count numbers:

// Define the total size of whatever you're looping. I get my data from MySQL,
// so this is just mysqli_num_rows() for me, but it can be whatever you want
$sizeArr = mysqli_num_rows($sth);

// Define Page
if (is_numeric($_GET['s'])) $start = $_GET['s'];
else $start = 0;

// I show 10 items in each scroll iteration
$end = $start + 10;

// Make sure we don't go past the length of the total
if ($end > $sizeArr) $end = $sizeArr;

If you're using Adsense / DFP then this Javascript function goes above the Infinite Scroll, or in a separate javascript.js if you prefer:

<script>
function showBanner(x) {
// Check to make sure the DIV exists
if (('#banner_' + x).length) {

// This is identical to the responsive that I created in the header, but with
// a dynamic slot[]
googletag.cmd.push(function() {
slot[x] = googletag.defineSlot('/xxxx/Responsive_Horizontal_Banner',
[[728, 90], [320, 50]], 'banner_' + x).
defineSizeMapping(horizontal_ad).
addService(googletag.pubads());

googletag.display('banner_' + x);
googletag.pubads().refresh([slot[x]]);
});
}
}
</script>

This next section is where we create what's going to be in the Infinite Scroll:

<div id="parentList">
<div id="itemList">

EOF;

if (is_numeric($_GET['counter']) $counter = $_GET['counter'];
else $counter = 0;

// This is how I did mine, but you can generate content ever how you want
for ($i = $start; $i < $end; $i++) {
// OPTIONAL: I show a banner on the first iteration of each loop
if ($i == $start) {
echo <<<EOF
<div id="banner_$counter"></div>
<script>
// On the first iteration, this loads showBanner(), but after that it's loaded
// in the callback function of loadMore(). I have no idea why I had to use
// setTimeout(), but it didn't work without it
setTimeout("showBanner($counter)", 100);
</script>

EOF;
}

// Here is where you'll show whatever other data you want to be in
// the Infinite Scroll
}

// Define the "next" page, INSIDE of the child container. In my example, I'm only
// creating the "next" page if there's anything left in the array, but you can create
// it any way you want as long as you send a starting number and, if you use the
// banners, a counter for the ID.
//
// This will be set to display: none by default, but you can play with it a little if
// you want to show an option for users without Javascript
if ($end < $sizeArr) {
$next_link = 'http://www.example.com/?';
$next_link .= 'counter=' . $counter . '&';
$next_link .= 's=' . $end;

echo <<<EOF
<a class="next" href="$next_link" style="display: none">next</a>

EOF;
}

echo <<<EOF
</div>
</div>

Beneath the parent container, you'll want to add these two tags (feel free to replace the "Loading more" text with an image, Javascript, or whatever you want):

<div id="loader">Loading more...</div>
<div id="start"></div>

Somewhere on the page (it doesn't matter where), define these variables on the page where you use Infinite Scroll:

var scroll = {
// REQUIRED: we're just defining them so leave the values are blank
controller : '',
scene : '',

// REQUIRED
// This is the ID of the parent container that will be appended
listID : '#parentList',

// This is the ID of the child container that will be looped
itemID : '#itemList',

// This is the CLASS assigned to the "next" link
nextClass : '.next',

// This is the ID of the "loading more" DIV
loadingID : '#loader',

// This is the ID of an empty DIV; once the user has scrolled to this point,
// the next page will start to load
startLoad : '#start',

// OPTIONAL: if you want the next page to start loading sooner, use this to
// move #start higher up the page. I chose to start loading 400px before the
// user reaches the bottom, which seems to work pretty well
padding : 400,

// OPTIONAL: I use this to show the ads
callback : 'showBanner',

// OPTIONAL: a counter is optional, but in case you want it I defined it. I have
// my example defined by $counter (in case a user starts with an "old" page
// number) and I increment by 1, but you can make these whatever you want
startCount : $counter,
increment : 1

// Note, if you remove any of the last optional variables, just make sure that the
// last one in the list does NOT have a comma (,) at the end
};
</script>

And then, finally, AFTER the end of the parent container and after the two empty tags, call the scroll() function:

<script>scroll();</script>


That's pretty much everything! I know it's a lot, but like I said it took me about a month to get it all working so I hope it helps.

I'm setting this thread to notify me of any replies, so if you need help then just reply and I'll help if I can. Or if you see any errors, modifications, or improvements, please post them for both my sake and any future reader!



[edited by: not2easy at 5:37 am (utc) on May 25, 2017]
[edit reason] fixed typo (at author's request) [/edit]

6:31 am on May 25, 2017 (gmt 0)

New User

10+ Year Member

joined:Feb 8, 2004
posts:8
votes: 1


[webmasterworld.com...]

Any example page to see how this works?

It sound like an Adsense policy violation...
6:54 am on May 25, 2017 (gmt 0)

Preferred Member

Top Contributors Of The Month

joined:Mar 15, 2013
posts:570
votes: 47


I'm still working in my sandbox right now and it's going to be awhile before I can go live with it. I used this as a guide for the ads, though, so it shouldn't be a violation:

[support.google.com...]

The earlier thread had the same problem that I originally experienced: that infinite scroll would only show 3 ads and then just blanks. Google changed their policy last year, though, and now has no specific limit on the number of ads; it just has to be proportionate to content:

[support.google.com...]

It looks like Adsense hasn't caught up to the policy update, though, which is why I had to go through DFP.

I sent the production page to my Google rep yesterday for verification, just to be sure that my page is OK, but I'm 99% sure that the above wouldn't be a violation.

I'll PM you with a link to the production page.
1:28 am on May 30, 2017 (gmt 0)

Preferred Member

Top Contributors Of The Month

joined:Mar 15, 2013
posts: 570
votes: 47


No word back yet from my Google rep, I guess cause it's Memorial Day Weekend.

But FYI, I did make one significant change that I wanted to share. I'm actually using the same script twice on one page (one to show content, another to show ads), so instead of duplicating content I simply send the object name to the function, like so:

scroll(scroll);

function scroll(scroll) {
...
setTimeout(loadMore(scroll), 1000);
}

function loadMore(scroll) {
...
}

Using this technique, I can define one object for the first scroll section, then another one for the second scroll section with a different name. I did find an advantage to calling the second one in a setTimeout:

var secondScroll = {
...
}

setTimeout("scroll(secondScroll)", 500);

While we're on the topic, though, any suggestions for ways to improve the user's CPU usage during an infinite scroll? I've found during testing that if I scroll down kinda fast, my CPU load quickly skyrockets from 2% to 100%. The pages have small images (10 70x70 images per iteration); would lazy-loading them help?
7:45 am on May 30, 2017 (gmt 0)

Preferred Member

Top Contributors Of The Month

joined:Mar 15, 2013
posts: 570
votes: 47


Optional modification: change browser URL as they scroll

In my case, I don't really want the user to bookmark a page that's further down the list; the content is regularly changing, and I would expect any bookmarks to be for the first page of results. But this would definitely make the page more search-engine friendly, and I'm working on making it better for the user to click "Back" and drop down to where they were (especially on a long page).

This is a fairly simple modification. I modified the var scroll object to include a new variable of:

pushstate : 1

I'm just using this as a boolean to make it optional; 1 is on, blank is off.

Then, in the loadMore() function, just above scroll.scene.update();:

if (scroll.pushstate)
// first param is an optional JSON string that can be used later; eg, {id: scroll.startCount}
// second param is the optional TITLE for the stored page
// third param is the LINK for the page
history.pushState(null, null, $(scroll.nextClass + ':last').attr('href'));

This will change the user's URL to whatever is in the last "nextClass" link that you created. So, in my example, it would change to www.example.com/?s=10, then www.example.com/?s=20, and so on.
5:43 pm on Aug 27, 2017 (gmt 0)

New User

joined:Aug 27, 2017
posts:1
votes: 0


Are you running this live yet? Is it allowed since you run it through DFP and have you received an answer from Google?
<snip>
I want to do the same, but not sure if I'm allowed.


[edited by: not2easy at 6:23 pm (utc) on Aug 27, 2017]
[edit reason] Please See ToS - No Links [/edit]

2:43 am on Aug 28, 2017 (gmt 0)

Preferred Member

Top Contributors Of The Month

joined:Mar 15, 2013
posts: 570
votes: 47


I haven't gone live yet, sorry... the last couple of months have been focused on trying to improve Adsense so the rebuild had to go to the backburner :-( I'm just now getting back to it.

To the best of my knowledge, though, it should be acceptable. I use a company on my main site to manage AdX, and their Google rep said it would be fine to use on all of my sites.
10:38 pm on Feb 5, 2018 (gmt 0)

New User

joined:Feb 5, 2018
posts: 1
votes: 0


Hi there,

I just wanted to ask - did you go live with your code yet? Are you able to get this working on a live website. Would really love to see a working example. And thanks for sharing your ideas.
6:14 am on Feb 8, 2018 (gmt 0)

Preferred Member

Top Contributors Of The Month

joined:Mar 15, 2013
posts: 570
votes: 47


I haven't gone live yet, I only get about an hour a day to program so it's taking forever :-( I'll send you a link to my sandbox, though
2:32 pm on Feb 8, 2018 (gmt 0)

Senior Member from US 

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month

joined:May 29, 2007
posts:803
votes: 95


It sound like an Adsense policy violation...


I don't believe it is. One of the top-ranked sites in my category has infinite scroll and many AdSense ads showing on the way down.