How to know when your ad tags stop loading, before the month-end report does

GAM reports cannot see a page that never asked for an ad. Here is what to check on the page itself, the three signals that catch a broken ad script within the hour, and a release checklist.

Four thin blue picture frames in a row on an off-white gallery wall; the third is empty, with only its hook and a dust outline.

A page that never asks for an ad does not show up in Google Ad Manager as a failure. It shows up as nothing. The request count for that ad unit goes down, the revenue line goes down, and both look like a slow day until someone compares the right two weeks. By then the broken template has been live for days. The only place a missing ad tag is visible on the day it breaks is the page itself.

This post is about watching the page.

How ad tags break without anyone noticing

The common cases, from what we see on publisher sites:

  • A template change drops the GPT script or a slot definition. A redesign ships, the article template loses the <script async src="https://securepubads.g.doubleclick.net/tag/js/gpt.js"> line, or one googletag.defineSlot call. The page renders perfectly. There is simply no ad in that position.
  • A div gets renamed. The slot is defined for div-gpt-ad-article-mid, the new markup calls it article-mid-ad. display() has nothing to draw into.
  • A tag manager change reorders the load. The consent tool now blocks the ad script until a choice is made, and on the first pageview of every session there is no ad call at all.
  • A Prebid upgrade changes a config key. Bidders drop out, the timeout changes, or the video cache points at a service that no longer exists. Prebid still loads, so a check that only confirms pbjs exists says everything is fine.
  • Lazy loading that never triggers. A rule that loads the slot when it scrolls into view, on a template where the slot is now below a fold nobody reaches.
  • An ad blocker signature matches your own code. A renamed script path or a class name that lands on a filter list.

None of these produce an error in Ad Manager. Two of them do not even produce an error in the browser console.

Three signals that catch it within the hour

Each of these can be checked by hand in a console, and each can be automated.

1. googletag is present and has the slots you expect.

typeof googletag !== "undefined" && googletag.pubads().getSlots().map(s => s.getAdUnitPath())

If the array is missing an ad unit path that the template should define, the slot was dropped. If googletag is undefined, the script never loaded.

2. Prebid is present and configured the way you shipped it.

typeof pbjs !== "undefined" && pbjs.getConfig()

Look at bidderTimeout, enableSendAllBids, and if you serve video, cache.url. Then pbjs.getBidResponses() after an auction: an empty object on a page that normally gets bids is a problem even though nothing is red.

3. The slot elements rendered.

Each ad slot's container should exist in the DOM and, after the auction, contain an iframe. An empty container after the page settles is the signal most dashboards never see: an ad request may have been made, but nothing rendered, or no request was made at all.

The difference between a page where these pass and a page where they fail is the difference between a normal Tuesday and a Tuesday that costs a week of revenue on your best template.

A release checklist for pages that carry ads

Give this to whoever ships the site. It takes five minutes per release.

  1. On the staging build, open one page of each ad-carrying template with the console open. Run the two snippets above. Compare the slot list with the list from production.
  2. Confirm ads.txt on staging is not about to overwrite production's file. Static site builds and CMS plugins do this more often than anyone admits.
  3. Check the consent tool's version and its load order relative to the ad script. If consent changed, test the first pageview in a private window from a region where consent is required.
  4. After deploy, load the same pages in production and run the snippets again.
  5. Write the release time next to the ad units it touched. When a drop appears in Ad Manager, that line is the first thing you will want.

When a synthetic check is not enough

A check you run from your own browser covers your own browser. It does not cover the visitor on an older Android build, the visitor in a country where the consent flow is different, or the section that gets most of its traffic from an app webview. The checks that matter run where the visitors are.

That is why PubPilot's on-page monitor runs as a small script on your pages. On real page loads it confirms that googletag and pbjs are present and that the ad slots you listed exist and render, and it tells you which domain, which page and which check failed. An empty frame on the sports template at 09:20 arrives in Slack at 09:31, which is a better time to find out than the first week of next month.

Questions people ask

Why does Google Ad Manager not show an alert when my ad tags break?
Ad Manager counts what reaches it. A page whose googletag script never loads sends no ad request, so there is nothing to report and nothing to compare. The drop only appears later as fewer requests, and only if someone compares the right days.
What should an on-page check actually test?
Three things on a real page load: that googletag exists and has defined the expected slots, that pbjs exists and has adapters configured if you run Prebid, and that each ad slot element is present in the DOM and has rendered. A check that only confirms the script tag is in the HTML misses the cases that cost money.
How often do pages need to be checked?
On every release at the least, and continuously on the templates that carry most of the revenue. Checks that run in real visitors' browsers catch what a synthetic test misses, such as a consent tool blocking the ad call for one region or a lazy-load rule that never fires on short pages.

Sources

More from the blog