How to serve other people’s ads on your own website — and why it is a completely different world from Google Ads.

1. The three names everyone confuses

Before anything else, we need to clear up a naming disaster. Google has three products whose names are almost identical, and mixing them up leads entire projects astray:

Product Who uses it What it does
Google Ads Advertisers (buy side) You buy ad space to promote your own business on Google Search, YouTube, and partner sites.
Google Ads Manager Account (MCC) Agencies & freelancers (buy side) An umbrella login on top of Google Ads. It runs no campaigns itself — it lets an agency manage many client Google Ads accounts from one dashboard (up to 85,000 linked accounts).
Google Ad Manager (GAM) Publishers (sell side) You sell ad space. It is an ad server: it decides, in real time, which advertiser’s creative appears in each slot on your website.

This article is about the third one: Google Ad Manager (GAM) — the platform you use when the ads on your site are not yours. You own the shelf space; advertisers rent it.

THE ECOSYSTEM — BUY SIDE vs SELL SIDE
BUY SIDE — spending money
Advertiser
↓ creates campaigns
Google Ads
↑ manages many accounts
Agency → MCC (Ads Manager Account)

SELL SIDE — earning money
Publisher / website owner
↓ manages inventory
Google Ad Manager
↓ serves ads into
Publisher’s website

⇢ demand can flow from the buy side into GAM via AdX / AdSense ⇠

The key mental shift: in Google Ads you think in campaigns, keywords, and bids to win someone else’s audience. In GAM you think in inventory, orders, and priorities to arbitrate between advertisers competing for your audience.

2. What Google Ad Manager actually is

Picture a digital billboard in a train station, where someone decides — at the very second you look at it — which poster to display. GAM is that “someone”: an ad server. It sits on Google’s infrastructure and waits. Every time a page on your site loads with an empty ad slot, the page raises its hand and asks: “I have a free slot, what should I display?” GAM looks at every campaign that could match, applies priority rules, and answers with the winning creative — or with an empty response if nothing matches (a no-fill).

Two halves make the system work:

  1. GAM (server side) — the brain. Holds your inventory definitions, the campaigns (orders and line items), the creatives, and the decision logic.
  2. GPT (Google Publisher Tag, site side) — the mouth. A small JavaScript library (gpt.js) embedded in your pages that describes each slot, calls GAM, and injects the returned creative into the right <div>.

GAM does nothing on its own. If GPT is not deployed on a page, that page generates zero ad requests and therefore zero impressions — no matter how perfectly the server side is configured. This is not theoretical: real-world audits regularly find sites showing 0 impressions for a whole quarter simply because the tag was never published on the production templates.

3. The building blocks (inventory model)

You describe your world to GAM with a small set of stacked bricks:

GAM OBJECT HIERARCHY
NETWORK
your GAM account — numeric code, e.g. 1234567
travels in every ad request
AD UNITS
the shelves — each has an address
/1234567/SITE_TOP_BANNER
↓ can be grouped into
PLACEMENTS (bundles sold together)
ORDERS (one per advertiser deal)
↓ contain
LINE ITEMS
which ad units · sizes · dates ·
priority · targeting
↓ carry
CREATIVES (image, HTML5, video)

↑ optional refinement ↑
KEY-VALUES — labels sent by the page: section=politics, pageID=1234

TL;DR — Network > ad units (path = matching key) > placements; orders > line items (targeting + priority) > creatives; key-values refine. GAM only reacts when a page asks.

4. The life of an ad request

Here is the full round trip — the thing you must be able to replay in your head when debugging:

AD REQUEST LIFECYCLE
① Visitor’s browser loads the page → page loads gpt.js
defineSlot('/NETWORK/UNIT', [[728,90]], 'div-id')
+ options: enableSingleRequest(), consent, lazy load
display('div-id') / refresh() → HTTP call
securepubads.g.doubleclick.net/gampad/ads
(unit path, sizes, key-values, consent signals)
GAM matches eligible line items, applies priorities, picks a winner
✅ A line item matches →
creative returned →
GPT injects it into the <div>
❌ Nothing matches (no-fill) →
empty response →
GPT collapses the <div> (height 0)

GPT performs three gestures, always in this order:

  1. Declare the slotgoogletag.defineSlot('/1234567/SITE_TOP', [[728,90]], 'div-gpt-top'): the exact ad unit path (same as in GAM), the accepted sizes, and the id of the HTML <div> that will host the ad.
  2. Set optionspubads().enableSingleRequest() (SRA), consent handling, lazy loading, collapseEmptyDivs().
  3. Firegoogletag.display('div-gpt-top') (or refresh()): only now does the real network call to gampad/ads leave the browser.

The golden rule: GAM and GPT must pronounce exactly the same ad unit path. If the page asks for an address GAM doesn’t know (typo, wrong path), GAM finds nobody and returns empty. The ad fails not because the campaign is misconfigured, but because the question was badly asked. Conversely — and this trips people up — an empty response with a perfectly correct path means the blocker is on the server-side matching (expired order, size mismatch, targeting, unverified site…).

TL;DR — defineSlot (path + sizes) → options → display() = one gampad/ads request. Path must match GAM exactly. Empty answer = no line item matched; the response body tells you more than the console.

5. How GAM decides: line item types and priorities

This is where GAM differs most radically from Google Ads. In Google Ads, an auction decides everything. In GAM, you define a waterfall of priorities, and the auction only fills what your direct deals leave over.

Line item type Priority (default) Typical use
Sponsorship 4 “Advertiser X owns 100% of this slot for the period” — share-of-voice deals, roadblocks, homepage takeovers
Standard 6 / 8 / 10 Classic guaranteed campaigns: deliver N impressions between two dates; GAM paces delivery automatically
Price Priority 12 Non-guaranteed: serves only if nothing above wants the impression, at a fixed price
Network / Bulk 12 / 16 Remnant fillers
House 16 Self-promotion, defaults when nothing else fills
AdSense / Ad Exchange backfill dynamic The programmatic auction competes for whatever direct sales don’t take

Lower number = higher priority. A Sponsorship (4) line always beats a Standard (8) line, which beats programmatic backfill. This waterfall is the entire point of GAM: it lets a sales team promise “your banner will be on the homepage all of March” and guarantee it against the open auction.

Contrast with Google Ads — there is no equivalent concept on the buy side. An advertiser in Google Ads can only bid harder; a publisher in GAM can simply decree who wins.

6. Configuration points, end to end

The practical checklist for setting up a GAM network, in the order that avoids rework.

6.1 Network level (Admin → Global settings)

6.2 Inventory

6.3 Tagging (the site side)

6.4 Privacy and consent (not optional in the EEA)

6.5 Trafficking a campaign (the daily workflow)

  1. Order — create one per advertiser deal (advertiser, salesperson, dates).
  2. Line item — choose type/priority, flight dates, goal (impressions or %), rate, then targeting: ad units and/or placements, geography, device, key-values. Two silent killers to double-check:
    • End date: an expired order stops serving everywhere, instantly — the #1 cause of “the ads suddenly disappeared”.
    • Key-value exclusions: a line excluding pageID = X is harmless while no page sends pageID, and becomes a bomb the day the site starts sending it.
  3. Creatives — upload one per booked size. A size declared in the page’s defineSlot but missing from the line item’s creatives = no match for that request (GAM only considers creatives matching the requested sizes during selection).
  4. Preview and check delivery after launch (see §8).

6.6 Opening up to programmatic (when ready)

7. Direct sold vs programmatic — the two revenue engines

WHO WINS THE IMPRESSION?
Ad request arrives (one impression on your site)
Any eligible direct line item?
YES — Sponsorship (4) / Standard (6-10) ↓
✅ Direct deal serves
price: as negotiated
NO, or only low priority left ↓
Programmatic auction
AdX / Open Bidding / Prebid
↓ winner beats floor / ↓ no bids
💰 Programmatic serves at auction CPM
or 🏠 house ad / collapse (no-fill)
Direct sold Programmatic
Who sells Your sales team, human negotiation Automated auction
Pricing Fixed (CPM/CPD/flat), agreed offline Dynamic, per impression
Booking Orders + line items, manually trafficked Demand connects via AdX/Prebid
Formats Anything you agree on (including custom sizes) Standard IAB sizes only, in practice
Guarantee Yes (Sponsorship/Standard) No
Typical role Premium inventory, brand deals Fill the remnant, price discovery

Mature publishers run both: direct deals take the premium slots at guaranteed prices, programmatic monetizes everything left over.

8. Debugging: the toolkit that actually works

GAM ships with excellent diagnostic tools; knowing them turns week-long mysteries into 5-minute checks.

Google Publisher Console — append ?google_console=1 (or ?googfc) to any page URL that loads GPT. A debug panel opens showing every slot, its unit path, the request status, and fill/no-fill per slot. Crucial detail: it only activates if the page already loads gpt.js — on an untagged page the parameter does nothing (which is itself a diagnostic: no console = no GPT = no requests). It works on production pages; it is a viewer, it changes nothing.

The Network tab — find the gampad/ads request. Read iu= (the requested unit path) and the sizes, and compare against GAM. A 200 OK with a tiny/empty body is a no-fill (Google’s docs: 200 = “an ad OR a blank response was returned”). An empty body with a correct iu means the blocker is server-side matching, not the tag. Also read the consent params: npa=1, rdp=1, ltd=1 = the request went out in limited-ads mode without TCF consent.

Delivery Tools → Inspect webpage ads — GAM’s native inspector: give it a URL and the line item you expect, and it returns Google’s official verdict (e.g. “Line item not found — the line item is not targeting as expected or is not serving”), plus a per-dimension targeting breakdown.

Ad Request Simulator — replays an exact captured request against the ad server and lists which line items were candidates. If your line is absent from the candidate pool while its targeting looks right, the block is upstream of the line item (site recognition, consent, network-level).

Line item → Troubleshoot tab — shows delivery causes (“line item always delivers, no non-delivery reasons”) and creative render rates.

Reports — a Domain × Ad server impressions report instantly reveals whether a site has ever served (a domain at 0 impressions over a quarter = chronic, structural problem, not a recent regression).

Field-tested failure catalogue

Real causes of “the ads don’t show”, roughly ordered by how often they bite:

  1. GPT never deployed on production templates — the site emits zero requests. Symptom: no gpt.js, no gampad/ads in the Network tab. Beware static <img> banners hardcoded in the CMS that look like ad serving but generate 0 GAM impressions.
  2. Order/line item expired — everything worked yesterday, empty responses today, on every domain at once. Check flight end dates first.
  3. Ad unit path mismatch — typo or wrong network code in defineSlot.
  4. Size mismatch — the page requests sizes the line item has no creative for.
  5. Site not declared/verified in Inventory → Sites — reserved campaigns can be blocked on unrecognized domains; the “Needs attention” badge means verification is incomplete (often because ads.txt is missing or wrong).
  6. ads.txt with a wrong publisher ID — worse than absent; blocks domain trust.
  7. Consent chain broken — no CMP/TCF on the page → ltd=1 limited mode → EEA demand restricted, CPMs crushed.
  8. Key-value exclusion trap — an exclusion that was dormant activates when the site starts sending that key.
  9. Test page vs production divergence — the test page has GPT but no CMP, production has CMP but different tags; you end up debugging a configuration that exists nowhere.

Method note: debug by differential. Compare a working page and a failing page captured at the same time (same request minutes). One variable at a time; every hypothesis must survive a hard proof (HAR capture, UI screenshot, official Delivery Tools verdict) before you act on it.

9. KPIs: publisher metrics vs advertiser metrics

Another deep difference with Google Ads. Advertisers optimize acquisition cost; publishers optimize yield.

Google Ads (advertiser) Google Ad Manager (publisher)
Impressions, CTR Ad server impressions, per domain/unit/advertiser
CPC — what a click costs you eCPM — what 1,000 impressions earn you
CPA / ROAS — cost per result Fill rate — % of requests that returned an ad
Quality Score Viewability (% of impressions actually seen — target 60%+)
Impression share (auction) Delivery/pacing — is a guaranteed line on track for its goal?
Conversion volume Programmatic vs direct revenue split

A publisher’s daily dashboard: impressions by site and unit, fill rate, eCPM by demand channel, viewability, and delivery health of guaranteed lines.

10. Quick-start checklist

11. Summary

Google Ads spends money to place your ads on other people’s screens. Google Ad Manager earns money by orchestrating other people’s ads on your screens — a server-side brain (network, ad units, orders, line items, creatives) paired with an on-page mouth (GPT) that must pronounce the exact same ad unit paths. Its superpower over any auction-only system is the priority waterfall: guaranteed direct deals always beat programmatic backfill. Its fragility is the number of silent single points of failure — an unpublished tag, an expired order, an unverified domain, a missing consent string — each of which produces the same symptom: an empty slot. Configure the foundations in order (inventory → sites/ads.txt → tags → consent → campaigns → programmatic), and learn the four debug tools; they turn every empty slot from a mystery into a diagnosis.