This is the order that causes the fewest problems. The step people are most tempted to skip is the last one, and it is the step that catches the mistakes made in the other four.
Step 1 — Put the script in the head, above the ad server
The wrapper must initialise before your ad server library requests anything. If GPT fires first, the auction has nothing to contribute and you will see bids in the console with no revenue in reporting.
<head>
<!-- Header bidding first. -->
<script async src="https://scripts.ssm.codes/your-slug.js"></script>
<!-- Then the ad server. -->
<script async src="https://securepubads.g.doubleclick.net/tag/js/gpt.js"></script>
</head>
async is correct here and does not create a race. The wrapper queues onto googletag.cmd and controls when the ad request actually fires, so load order of the two files does not matter — what matters is that the ad request is gated on the auction.
Step 2 — Define your placements
One ad unit per auctionable position. Each needs a stable identifier, the sizes it can accept, and the ad server path it corresponds to.
Two decisions here have outsized consequences. Be honest about sizes: declaring 300×600 on a slot that is physically 300×250 produces bids you cannot render and inflates your discrepancy. And separate above-the-fold from below-the-fold units, because you will want different timeouts, different floors and different lazy-load behaviour for each.
Step 3 — Connect demand
Every bidder needs its own parameters — usually a publisher ID plus a placement or zone ID per ad unit. These come from the SSP after you sign with them, and getting one wrong fails silently: the bidder simply never bids, and there is no error.
Start with three or four bidders you have real relationships with. More is not better past a point; each additional adapter adds bytes to the bundle and requests to the page, and the incremental bidder that wins 0.4% of auctions is costing every user something.
Step 4 — Create the line items
This is the part that surprises people who expected header bidding to be self-contained. The ad server has to be taught to read the auction result. In Google Ad Manager that means price-priority line items keyed on the wrapper's targeting values — conventionally hb_pb for the price bucket and hb_bidder for the winner.
You need one line item per price bucket, which is why this is normally done with a generated sheet and a bulk upload rather than by hand. Granularity is a trade-off: finer buckets capture more of each bid but multiply the number of line items you have to maintain.
Step 5 — Verify
-
1
Append
?pbjs_debug=trueto a page URL and check the console: you should see bid responses, with timings, per bidder. -
2
Open the Google Publisher Console and confirm the
hb_pbandhb_bidderkey-values are actually present on the ad request. - 3 Confirm a header bidding line item is being selected when the bid beats your direct demand. Bids arriving but never winning almost always means a line item targeting mismatch.
- 4 Check your unfilled rate before and after. It should not go up.
- 5 Check LCP on a real mobile device, not just in the lab. This is the number that tells you whether your timeout is defensible.
On ssm.codes specifically
Steps 2 to 4 are dashboard configuration rather than code: you define placements and bidders in the panel, and the platform compiles a single tag and republishes it to the CDN in under ten seconds. Step 1 is still one script tag you paste into your template, and step 5 is still yours — nobody can verify your Core Web Vitals for you.
Related questions
Where exactly should the header bidding script go?
In <head>, before your ad server library. It can be async. The wrapper does not need to finish loading before GPT — it needs to be the thing that decides when the ad request fires, which it does by queueing onto googletag.cmd. Putting it in the body or after the first ad call is the most common cause of zero header bidding revenue.
How long does a header bidding setup take?
Technical installation is hours, not weeks. The slow parts are commercial: SSP applications and approvals typically take one to three weeks each, and building the line item structure in your ad server takes a day the first time. Plan for a month end to end if you are starting with no SSP relationships.
Do I need to change my existing ad slots?
Not necessarily. If your slots are already defined in your own page code, header bidding units can attach to them instead of replacing them, so your templates stay untouched. Whether that is the right choice depends on how much control you want over slot definition.
How many bidders should I start with?
Three or four with real contracts. Each adapter adds bundle size and network requests, and the returns fall off quickly — the sixth bidder rarely pays for the latency it adds. Add more only when reporting shows a bidder is winning enough auctions to justify its cost.
Try it on your own site
Free up to 1 million ad impressions a month. You keep your Ad Manager account and your SSP contracts.
Start free