Fixing AdSense Site Authorization Problems on Messy Domains

Fixing AdSense Site Authorization Problems on Messy Domains

When AdSense Decides Your Site Isn’t Yours

There was a week in 2022 where all my site earnings flatlined. Just vanished off the reports. What’s worse, fill ads were serving fine, but the revenue was a ghost town. Spoiler: it was an AdSense “site not authorized” problem, but it wasn’t obvious because nothing really broke visually.

This can creep up on you when you’ve got multiple subdomains, AMP variations, or reverse proxies. The main AdSense “Sites” settings look simple—either you authorize ad requests from a verified domain or you don’t. But misconfigure a single CNAME or load ads via iframe from an unlisted host and boom: you’re giving away impressions to the void.

Important quirk: if your ad code lands on a site that isn’t in your authorized list, AdSense might still render the ad, but earnings won’t track. There’s zero alert—no email, nothing in the Policy Center. It just silently cuts you off. This especially sucks when working with third-party CMS setups where you don’t control domain routing cleanly.

Actual aha moment: I caught it via developer console. Checking google_ad_client and comparing document.location.host — didn’t match what AdSense considered authorized.

Subdomains, Subdirectories, and the Lies We Tell Ourselves

Here’s where a decent chunk of people mess up: AdSense treats blog.example.com as entirely separate from example.com in the Sites panel. If you verified example.com in Search Console, AdSense won’t assume your subdomains are fine too. You actually have to go into AdSense → Sites → Add Site → and add each fully-qualified subdomain. Yes, really. Even if it’s routing traffic through the same backend, it won’t count unless you explicitly add it.

Subdirectories are safer, but things get wobbly when you’re proxying third-party content. I had an AMP cache going through /amp-story but served from a Cloudflare Worker tunneling into another zone. That broke authorization because technically it hit amp.example.workers.dev before whitelisting the response. Guess what wasn’t listed in Sites? Yeah.

Soft rule I’ve landed on: If the browser’s window.location.hostname isn’t whitelisted, you’re invisible to AdSense.

CDNs and Reverse Proxy Gotchas

Cloudflare is amazing—until one of your proxies starts doing something “helpful” and starts rewriting headers. If you’re using a reverse proxy and your actual domain forwards to another backend (for example a WordPress multisite or a headless CMS), AdSense treats the immediate URL origin as the authority.

I’ve seen this break when:

  • Serving AMP from CDN-defined vanity subdomains
  • Caching pages with embedded AdSense script on the edge
  • Using Response.redirect inside service workers for staging vs. prod
  • Embedding ads via <iframe> from an off-site SSR layer
  • Deploying Netlify or Vercel previews with ads still enabled (they shouldn’t be)

AdSense sees the host, not whatever shows up in the user’s browser bar after redirects. That means if the ad script runs from my-preview.netlify.app, your verified example.com means nothing. You have to add the Netlify subdomain too, which clearly isn’t a good idea for staging environments. Instead, you should block ads from initializing during previews altogether.

Third-party Platforms and AdScript Injection

If you’re using Squarespace, Shopify, or Ghost, you might not realize that some of them serve your page via a façade domain and rewrite the response behind the scenes. A lot of these platforms show your domain in the bar, but technically serve content out of a core hosting domain beneath it.

Shopify, especially, has some hosted apps that inject AdSense via an iframe from a shopify.com CDN. Unless you’ve whitelisted that CDN domain in AdSense’s Site list, you’re losing money. Or worse: someone else might accidentally benefit from your client ID if their traffic matches the CDN domain properly.

Weirder still: there’s no obvious console error. You’ll see ads. Clients will be happy. But the next day, your revenue will show hundreds of impressions and two cents in matched content revenue. That’s your clue. If your RPM plunges but impressions remain steady, dig into which domain is requesting those ad slots.

Verifying Ownership is a Delayed Nightmare

So adding a site in the AdSense panel is easy enough… unless you’re locked into Search Console verification hell. AdSense requires that a site be verified as owned via Search Console before you can authorize it for ads. But Search Console itself can lag painfully when verifying subdomains—especially when DNS TXT records take ages to propagate or you’re stuck behind a managed DNS layer (like if your registrar wraps DNS settings behind a UI abstraction).

One of the dumbest things I ran into: I added cdn3.my-domain.com to AdSense Sites, went to Search Console to add a property, and it refused to verify via HTML file even though the file was served properly. Eventually found out it was cached differently for crawlers by my service worker—it stripped HTML extensions from GET requests unless they had a trailing slash.

{
  "status": 404,
  "error": "Not Found",
  "url": "/adsense-verification-file.html"
}

That page existed. It just got intercepted before GoogleBot could reach it.

Ad Blocking Weirdness and Authorization Confusion

This one took me a drunk Saturday afternoon to even suspect: uBlock Origin (and some anti-ad implementations like Brave’s Shield) will block requests to pagead2.googlesyndication.com, but still let some fallback ad markup render dummy containers especially in testing modes. And if you’re running your own user-agent tests, you’ll fall into the trap of assuming things work because the browser doesn’t complain — but AdSense logs the request as originating from an unauthorized source and discards it anyway.

One particularly bad test loop happened when I had ads rendering inside Google Tag Manager and forgot that I was testing the GTM container on a staging subdomain (dev.example.com) not on production. GTM loaded the AdSense code just fine. My test ad rendered. But again: not in the authorized Sites list. That entire test suite was a waste of two happy hours.

Advanced Detection: Logging Request Hosts from the Ad Code

If nothing else helps, use this snippet

If you’re debugging where your ad requests are originating—and which site AdSense thinks the request is *from* (not where it ends up)—log what hostname and referrer the script actually executes in. This helped me finally isolate a proxy stack that was breaking ads for a user who had reverse-proxied my widget.

<script>
(function() {
  var origin = window.location.hostname;
  var referrer = document.referrer || 'none';
  console.log('Ad request from:', origin);
  console.log('Referrer seen as:', referrer);
})();
</script>

This doesn’t solve anything directly, but it tells you whether AdSense is likely to throw your request away because it came from an unknown domain. If you see any hostname you don’t explicitly remember adding through Search Console and the AdSense Sites panel, that’s where to start fixing.

You Can’t Whitelist Wildcards. Stop Asking.

People keep asking whether you can add *.example.com to simplify subdomain authorization. You can’t. AdSense requires you to add each fully-qualified subdomain manually. Yes, it’s annoying. No, you can’t run a script to add them automatically.

There’s a product logic flaw here. AdSense doesn’t allow wildcard domain authorization with the rationale of “preventing abuse”. But this forces multi-subdomain deployments (think: help.example.com, app.example.com, media.example.com) to manually queue up domains even if they belong to the same verified Search Console account.

Undocumented note: If you authorized a root domain and later serve ads via an empty iframe on a subdomain, AdSense flags it as unverified even if it’s just hosting content from the main one. I tested it — iframe didn’t pass the origin match.

Similar Posts