If An Ad Shows on A Website, And Nobody Sees It, Does it Still Make Money?

Billboard by Curbly on Instagram
From our 2015 Yellowstone road trip. Follow us on Instagram!

There's this billboard near the off-ramp I take almost every day on my way home from work, and it always makes me chuckle. See, the highway, at that point, has a pretty high sound barrier along the east side, which makes it impossible for anyone driving north to see more than about half of that billboard.

I drive by it, day after day, wondering what it might be trying to advertise to me. Sometimes, if I'm lucky, the company's logo will be on the half that I can actually see, so I know, for example, that McDonald's wants to sell me something, but I'm not sure exactly what, or at what price. Is it chicken nuggets? A Big Mac? A Big Nugget? A Chicken Mac?

What are you trying to say to me, billboard?!!!

It's chicken nuggets, all the way down.


When I realize my windows are down and other drivers can probably hear me, I try to calm down and move on to other concerns, but the question remains: who would spend money to advertise on that billboard? No one can even see it!

Well, interestingly, this question has become especially relevant to me recently. See, Curbly makes a big chunk of its revenue from billboards. Not on highways (I wish ... with the cherry pickers and the giant letters and the ...), but on Web pages. And although we don't have sound barriers on the internet (again, I wish), there is a question about who actually sees your advertisement when you pay to have it shown on Curbly (or anywhere else).

It's called viewability. A stupid term, I know. But online advertising seems to have been created primarily to support stupid jargon and acronyms, and only secondarily as a way to make money.

Why viewability matters so much to publishers and advertisers alike

Viewability means the same thing online as it does on the side of the highway: how many people can actually see my advertisement? For billboards, it's not that easy to measure. You'd have to drive around to every one, check it from a bunch of angles, count how many cars are going by.

But for digital advertising, it's not that hard. Your browser can measure which parts of the screen are viewable, and for how long. If Curbly shows an ad at the bottom of this page, but you never scroll past the first paragraph (What?! Why? You don't like me? Why aren't you reading my beautiful blog post!?), then you'll never see that ad. And that advertiser, rightly, isn't going to want to pay for it.

McDonald's shouldn't be paying for that half-a-billboard near my house, and they certainly are justified in not wanting to pay for a banner ad that was never even in the viewable area of the browser.

So why, as the publisher-slash-billboard-owner, should I care about this? After all, it's better to get paid for those unviewed ads, isn't it?

Well, yeah, kinda. At least, it used to be. For a long time, no one (including the publishers) was really measuring that statistic. But in the last few years, viewability has become a must-have metric for online advertisers and publishers alike.

But there's more to it. In fact, un-viewed ads never helped publishers that much. Sure, maybe we got paid for them before, but because they were never viewed the CTRs (click-through-rates) were always terrible, which meant the CPMs (cost-per-mille, or amount earned per thousand times that ad is served) were terrible. And those ads, viewable or not, added to our page latency (load time), which annoyed visitors and lowered our TOS (time-on-site).

(Remember about the stupid jargon and acronyms? I wasn't kidding about that.)

So ads with very poor viewability hurt publishers too, both in terms of the revenue they generate, and in the user experience. Plus, as a publisher, you want advertisers to view your space (your 'billboards', if you will) as premium quality. Those low quality placements were dragging down the perception of quality for all our ad spaces.

Fortunately, there's something we can do. 


Lazy loading
My kind of chart
Photo: Phill Venditti

Lazy loading - an approach to improving ad viewability

It's called lazy-loading. Lazy-loading means, simply, not loading something on the page until you absolutely, positively have to. Kind of like how I do laundry, or bathroom cleaning, or taxes.

We already do this for images, by the way, and have for a few years. Images are an important part of our site (it's possible, though it hurts my pride to admit it, that some of you are just skimming the text of this article, and mostly looking at the pictures), but they have a big impact on that page latency number. Basically, they're big (file-size wise), and take a long time to load. That costs us in latency and money (we pay for the bandwidth), so why load images that no one ever scrolls down to see?

So we use a javascript library (it's called Lazysizes), that does all kinds of magic in the background to load our images only when you're about to actually see them. It's a little more complicated than that; we actually load a low-resolution version of every image right away, and then Lazysizes swaps that out for a higher-resolution version at the last possible moment. But the idea's the same: the effect is that we don't waste time or money serving up high-resolution images that you aren't going to look at.

And, awesomely, Lazysizes works just fine with our ad serving code, too. We use Google's DFP (Doubleclick For Publishers) as our ad server. DFP gives us these little snippets of Javascript that we sprinkle throughout the site – like fairy dust! - and those do the job of getting the right advertising creative (what you see on the billboard) for each and every user. They look like this:

googletag.cmd.push(function() { googletag.display('div-gpt-ad-123456-0'); });


Aside: yes, those little fairy dust sprinkles do actually serve a different ad for every visitor, depending on their location, device, time of day, and a million other factors. And yes, that's why if you go looking for new shoes on Zappos, you will then see ads for those exact shoes on every Web site you look at for the next few weeks, or until you clear your browser cookies.

Normally, when you implement those DFP tags, they tell the browser to go ahead and load all the ads right away. All we have to do is include one line of code that tells it not to do that:


Obstruct and delay, FTW!

Now we modify our ad setup snippet just a little:

window.leaderboard = googletag.defineSlot('/123456/leaderboard', [[728, 90]], 'div-gpt-ad-123456-0').addService(googletag.pubads());

That puts the ad slot definition into a global variable we can access later.

Then we change the way we code the actual ad slot:

<div id="div-gpt-ad-123456-0" class="lazyload" data-ad-slot="leaderboard">
  googletag.cmd.push(function() { googletag.display('div-gpt-ad-123456-0'); });

That 'data-ad-slot' attribute is just there to denote which ad slot definition this snippet should call when the time comes. 

Now, we configure Lazyimages to do something special when it sees that one of those code snippets is about to come into view:

document.addEventListener('lazybeforeunveil', function(e){
    var ad_slot = e.target.getAttribute('data-ad-slot');
      googletag.cmd.push(function () {
        googletag.pubads().refresh([ window[ad_slot] ]);

We listen for the custom event that Lazysizes emits whenever an element with the 'lazyload' classname is about to come into the viewport. If that element has a 'data-ad-slot' attribute, then it's an ad snippet, so we tell DFP to refresh (or, since it was never loaded, fetch) that ad slot.

Boom! Simple as that; now our ad slot isn't loaded until it's about to be viewable in the browser window, meaning our viewability metrics go up, which means advertisers will want to pay more for those ad impressions.

True, it also means our overall number of ad impressions goes down. But as I said above, that not really a bad thing, since we're just losing the ad impressions that were never getting seen (or making much money) anyway, and cutting down our page load time in the process.

Does it work?

I just implemented this change last month, so I don't have great numbers to back this up, but I'm pretty confident this is going to be a good thing for us (I'll check back later this quarter when we've had a chance to see how things have played out).

Here's a comparison of our viewability percentage and impressions for one ad slot, before and after the change:

Viewability change after implementing lazy loading


Clearly, viewability went way up, impressions are down. Are we making less money? Nope. Here's the CPM before and after:

CPM lazy loading

That ad slot CPM went way up! Meaning, we're making more money per thousand impressions. So the higher CPM makes up for the lower impressions. In fact, it more than makes up for it. We're actually making more money on that ad slot, per day, than we were before.

Ok, it's a little more complicated than that; we're still trying to work out some details about how to make lazy loading ads work with our header bidding adapter (Prebid.js). And there are so many factors involved in our advertising performance that it's tricky to isolate and analyze the effects of a change like this. 

More importantly, this seems to me like technology that should be built in to the ad server (in our case, Google's DFP), not tacked on by the publisher. I think we'll probably see the big players in the programmatic ad-serving space start to address this soon, giving publishers an even easier way to ensure they're not showing chicken nugget ads to people who can't even see them.


Tired of watching your ad revenues fluctuate randomly? Maybe you need to focus more energy on sponsored content revenue. Lucky for you, I've got a free, seven-day sponsored content crash course, and you can sign up today.



(2000 character limit)

bruno on Sep 21, 2017:

Hi Mayra,
We actually switched our ad inventory management over to a third party (they use Prebid.js too, but I'm not in charge of the implementation anymore). Sorry!

Mayra on Sep 20, 2017:

Great article and insight, thanks for sharing! I started implementing this but my concern was the header bidding. Is there an update to see if lazy loading ads work with header bidding Prebid.js?

bruno on Feb 13, 2017:

Looks like the 'display: none' on your ad divs is causing that. If you remove that from the style attribute on the divs, it seems to work fine.

bruno on Feb 10, 2017:

Hi Edgar,
Unfortunately I don't; the ad integration is going to be very specific to each site, I don't think there's a way to just grab what we do and port it directly over. I'm happy to look at some code samples of yours though, and try to help out.

Edgar Muring on Feb 10, 2017:

hi bruno,

iv just read your article about ads viewability and was trying to implement it on my site. but somehow the ads doesnt display.

do you have a complete example code that i can learn from?


All comments
Comments RSS