Header bidding

Prebid.js setup, from download to your first bid in Ad Manager

Prebid.js setup for publishers: build your own file, add bidders, match price granularity to Ad Manager line items, then test every bid before launch.

MH AdX title card for a Prebid.js setup guide, showing the steps from download to Google Ad Manager

Prebid.js setup takes five steps: build a Prebid.js file with only the bidders you use, add it to your pages above Google Publisher Tag, define your ad units and bids, create matching key-values and line items in Google Ad Manager, and test every bid before launch. Ad Manager 360 networks can skip the line items with header bidding trafficking.

Here's the catch. Prebid.js is free and open source, but nothing in it checks your work. A page can send bid requests all day while Ad Manager never lets one win, because the price buckets in your code don't match the line items in your ad server. Nobody sees an error. You just earn less than you should.

This guide walks through the setup in the order we do it when we add header bidding to a publisher's site, using Prebid's and Google's current docs.

What you need before the Prebid.js setup

You need three things in place first: an ad server, signed bidders, and access to edit your site's code. Without all three, Prebid.js has nothing to send bids to.

  • Google Ad Manager with Google Publisher Tag (GPT). Prebid collects bids, then hands the best ones to your ad server as key-values. AdSense can't take them. If you're still on AdSense, our guide to getting Google AdX access covers how publishers usually move to Ad Manager.
  • Contracts with your bidders. Each SSP or exchange gives you its own IDs (a placement ID, site ID or zone ID). You'll paste these into the bid parameters. No IDs, no bids. If you're still picking partners, see how to choose an SSP and test it first.
  • Their ads.txt lines. Each bidder also sends you one or more ads.txt lines. Add them before launch. Buyers skip sellers your ads.txt doesn't list, and our ads.txt guide for publishers explains each field.
  • A consent management platform (CMP) if you get traffic from the EEA, the UK or US states with privacy laws.
  • Someone who can edit the page template and a staging page you can test on.

If header bidding itself is new to you, our guide to programmatic advertising for publishers explains where it sits next to AdX and Open Bidding. It's a quick read and saves confusion later.

The Prebid.js setup steps at a glance

The Prebid.js setup splits into a page side and an ad server side. Developers handle the page; ad ops handles Ad Manager. Both sides have to agree on price buckets and key names, or bids won't win.

  1. Download Prebid.js as a custom build with your bid adapters and modules.
  2. Load it on the page, together with GPT, and set up the command queues.
  3. Define your ad units and bids, then call pbjs.requestBids.
  4. Set price granularity, the timeout and consent with pbjs.setConfig.
  5. Pass the bids to GPT with setTargetingForGPTAsync and refresh the slots.
  6. In Ad Manager, create key-values, an order, line items and creatives (or turn on header bidding trafficking on Ad Manager 360).
  7. Test with Prebid's debug mode and Professor Prebid, then roll out.

Prebid's own getting started page says the same split: download "the Prebid.js package, including your selected bidders and adapters," add it to your page, and agree price granularity and key-value pairs with your ad ops team.

Step 1. Download Prebid.js as a custom build

Don't use a generic Prebid.js file. Build one that holds only your bidders and the modules you need. Every adapter you don't use is extra code that every visitor downloads.

You have two ways to get the file. Most publishers should start with the first.

Option A. The download builder

Go to Prebid's Customize and Download Prebid.js page. Pick a Prebid version, tick the bid adapters for the SSPs you've signed, and tick the modules you need. The page notes that "recommended modules are now checked by default," so read that list before you untick anything. Then download the file and host it on your own domain or CDN.

At the time of writing, the latest release on the Prebid.js releases page on GitHub was 11.44.0, from 24 October. Prebid ships updates often, so check the page and note your version somewhere your team can find it.

Option B. Build from source

If your developers want builds in version control, they can build from the Prebid.js GitHub repository. The README gives the commands. You need Node.js and the gulp command line tool:

git clone https://github.com/prebid/Prebid.js.git
cd Prebid.js
npm ci
npm install gulp-cli -g
gulp build --modules=rubiconBidAdapter,openxBidAdapter,consentManagementTcf,gptPreAuction

The module names here are only examples. Use the adapters for the bidders you've actually signed. You can also list them in a JSON file and run gulp build --modules=modules.json, which is easier to review in a pull request. The finished file lands in the build folder (build/dist/prebid.js).

Watch out: Prebid's basic example loads a copy from a public CDN and warns it's "a test version of Prebid.js hosted on our CDN that is not recommended for production use." Copying that script tag into a live site is one of the most common mistakes we find.

Step 2. Add Prebid.js and GPT to the page

Load Prebid.js and GPT in the <head>, both async, and set up their command queues straight away. The queues let you write code before either library has finished loading.

<script async src="/js/prebid.js"></script>
<script async src="https://securepubads.g.doubleclick.net/tag/js/gpt.js"></script>
<script>
  var pbjs = pbjs || {};
  pbjs.que = pbjs.que || [];
  var googletag = googletag || {};
  googletag.cmd = googletag.cmd || [];

  // hold GPT until Prebid has bids (or times out)
  googletag.cmd.push(function () {
    googletag.pubads().disableInitialLoad();
  });
</script>

That disableInitialLoad line matters. Google's GPT reference says it "disables requests for ads on page load, but allows ads to be requested with a PubAdsService.refresh call." Without it, GPT calls Ad Manager before Prebid's bids arrive, and header bidding never gets a chance. Google's reference now marks this method as deprecated in favour of the page-level disableInitialLoad setting in googletag.setConfig. Either one does the job; Prebid's example still uses the older call.

Step 3. Define ad units and bid adapters

Ad units tell Prebid which slots to auction, which sizes they take, and which bidders to ask. Use the same ad unit path or div ID that GPT uses for the slot, so Prebid's bids land on the right slot. If you're still choosing which display slots to run, read our programmatic display advertising guide first.

var adUnits = [{
  code: 'div-gpt-ad-top',            // same as the GPT slot's div ID
  mediaTypes: {
    banner: { sizes: [[728, 90], [970, 250]] }
  },
  bids: [
    { bidder: 'bidderA', params: { placementId: 'ID-FROM-BIDDER-A' } },
    { bidder: 'bidderB', params: { siteId: 'ID-FROM-BIDDER-B' } }
  ]
}];

Each bidder's adapter page on docs.prebid.org lists its exact parameter names. They differ from bidder to bidder, and one typo means that bidder silently sends nothing. Copy the names from the adapter page, not from an old email.

A few rules we follow for ad units

  • List only the sizes the slot can really show. Extra sizes add bids that can't render well.
  • Start with three to five bidders you know have demand for your traffic. Adding a tenth bidder rarely beats tuning the first five. Pick bidders that bring different demand, though: two adapters that resell the same buyer give that buyer room to shade its bid lower in a first-price auction.
  • Below-the-fold slots can be auctioned later, when they get near the screen (lazy loading). Prebid lets you call requestBids for any set of ad units at any time.

Use pbjs.setConfig to set three things before the auction: the price buckets, how long bidders get, and consent. Price granularity is the setting that has to match your Ad Manager line items exactly.

pbjs.que.push(function () {
  pbjs.setConfig({
    priceGranularity: 'medium',     // must match your line items
    bidderTimeout: 1000,            // ms; tune after testing
    consentManagement: {
      gdpr: { cmpApi: 'iab', timeout: 8000 }
    }
  });
});

Prebid price granularity, and how many line items each option needs

Prebid rounds each bid down into a price bucket, and Ad Manager needs one line item per bucket. Prebid's price granularity page says bids "are rounded down according to your price granularity." So the finer the buckets, the more line items you create.

The options and increments below come from Prebid's setConfig reference. We worked out the bucket counts from those increments.

SettingIncrements (from Prebid's docs)CapBuckets, so line items per set
low$0.50$510
medium (default)$0.10$20200
auto$0.05 to $5, $0.10 to $10, $0.50 to $20$20170
dense$0.01 to $3, $0.05 to $8, $0.50 to $20$20424
high$0.01$202,000

"Per set" means one set for the top bid only, or one set per bidder if you send all bids. Prebid's Ad Manager step-by-step guide notes a limit of "450 line items per order." So high needs at least five orders per set, and dense only just fits in one.

Our view: auto or dense suit most sites, because they're fine-grained where most bids land (under $5) and coarse above it. And rounding isn't lost money. Prebid says "rounding does not impact the price paid, only the auction on the ad server." It does matter for winning, though. In Prebid's own example, a $2.75 bid rounded to $2.50 "could lose to an ad server bidder that bid 2.51."

Prebid timeout

The timeout is how long bidders get before Prebid closes the auction and calls Ad Manager. Prebid's docs show bidderTimeout: 3000 as an example and don't recommend one number. They also warn that "it's possible for the timeout to be triggered later than expected" on a busy page.

We start around 1,000 ms and adjust once we can see real response times. Too short and good bidders get cut off. Too long and your ads load late, which hurts viewability and user experience. Keep a separate failsafe timer a little above the timeout, as Prebid's basic example does, so GPT still runs if something breaks.

Prebid's modules page says "Prebid.org highly recommends" a short list of modules. It includes the TCF and GPP consent management modules, TCF Control, GPP Control for US states, Storage Control and GPT Pre-Auction. The TCF consent module fetches "the user's GDPR & Google additional consent data from the CMP" and passes it to the bidders. Without it, EEA bidders get no consent string and bid less, or not at all. Ask your legal adviser which modules your traffic needs.

Step 5. Connect Prebid.js to Google Ad Manager

When the bids are back, Prebid sets key-values on each GPT slot, and then you refresh the slots so GPT calls Ad Manager with those values. This is the hand-off at the heart of every Prebid.js Google Ad Manager setup.

var FAILSAFE_TIMEOUT = 3000;

pbjs.que.push(function () {
  pbjs.addAdUnits(adUnits);
  pbjs.requestBids({ bidsBackHandler: sendAdServerRequest });
});

function sendAdServerRequest() {
  if (pbjs.adserverRequestSent) return;
  pbjs.adserverRequestSent = true;
  googletag.cmd.push(function () {
    pbjs.que.push(function () {
      pbjs.setTargetingForGPTAsync();
      googletag.pubads().refresh();
    });
  });
}

// GPT still runs if bids never come back
setTimeout(sendAdServerRequest, FAILSAFE_TIMEOUT);

googletag.cmd.push(function () {
  googletag.defineSlot('/1234567/top-leaderboard', [[728, 90], [970, 250]], 'div-gpt-ad-top')
    .addService(googletag.pubads());
  googletag.pubads().enableSingleRequest();
  googletag.enableServices();
});

This follows the structure of Prebid's basic example. Change the ad unit path and sizes to your own. The adserverRequestSent flag stops the slot being requested twice when both the bids and the failsafe fire.

Step 6. Create Prebid line items in Ad Manager

Ad Manager only lets a Prebid bid win if a line item targets that bid's price bucket. So the classic setup is one order (or a few) full of price priority line items, each targeting one hb_pb value. Here's the order from Prebid's step-by-step guide.

Create the keys

In Ad Manager, go to Inventory > Key-values and create the keys Prebid sends, such as hb_pb, hb_adid, hb_size and hb_format. If you send all bids, you also need per-bidder keys like hb_pb_bidderA. Prebid's guide notes that key names are cut to 20 characters, so check long bidder codes.

Send top bid or send all bids

Send top bid passes only the winning Prebid bid per slot. It needs one set of line items. Send all bids passes every bidder's bid under its own keys. That gives better reporting by bidder, but multiplies your line items by the number of bidders. For most sites starting out, we'd pick top bid and add per-bidder reporting later.

Create the order and line items

  1. Create an advertiser called something like "Prebid", and an order under it.
  2. Create a line item with type Price priority (12), start time "Immediately," end time "Unlimited" and goal type "None," as Prebid's guide sets out.
  3. Set the rate to the bucket price, for example $1.20.
  4. Target the key-value hb_pb = 1.20 (or hb_pb_bidderA = 1.20 for send all bids).
  5. Add the creative sizes the slot uses.
  6. Repeat for every bucket. A medium granularity set means 200 of these.

Nobody should click through 200 line items by hand. Prebid's step-by-step page links to its Line Item Manager tool, and Ad Manager's API can create them in bulk. Either way, check a sample of rates and targeting afterwards.

Add the creative

Each line item needs a creative that renders the Prebid ad, built on the Prebid Universal Creative. Copy the current creative code from Prebid's docs, not from an old blog post, because the recommended code has changed over the years. Set the creative to the slot sizes, and serve it in a SafeFrame unless a bidder tells you otherwise.

Header bidding trafficking on Ad Manager 360

If your network is on Ad Manager 360, you can skip Step 6. Google's header bidding trafficking feature lets Prebid bids compete at their true price without any line items. Google's help page on header bidding trafficking with the Prebid wrapper says it's "only available in Google Ad Manager 360."

Prebid's header bidding trafficking guide says it plainly: "You don't have to set up any line items, including price priority line items." The requirements, from both pages:

  • Ad Manager 360.
  • A "standard implementation" of Prebid.js, where GPT can find the Prebid global object.
  • Google Publisher Tag on your site.
  • The Banner ad format and the Web inventory type.

To turn it on, go to Delivery > Bidders, open the Header bidding card, choose "Go to Prebid Wrapper," then "Get started." You review each bidder Ad Manager found, then pick "Run Prebid on entire network" or run an experiment on part of your traffic first. We'd run the experiment.

The header bidding trafficking FAQ says "traditional header bidding setups will continue to function," and the two can run side by side. In reports, these impressions show under the demand channel "Header bidding." If you're on the free Ad Manager edition, the line item setup in Step 6 is still the way.

Step 7. Prebid debug and testing before launch

Test on a staging page with Prebid's debug mode first, then on a small share of live traffic. Most problems show up in the first ten minutes of testing.

Use Prebid's debug tools

Prebid's troubleshooting guide says to add pbjs_debug=true to the end of your page's URL. Then open the browser console and run these:

Console callWhat it tells you
pbjs.versionWhich Prebid.js version the page loaded
pbjs.getConfig()Your timeout, price granularity and other settings
pbjs.adUnitsThe ad units Prebid knows about
pbjs.getBidResponses()Every bid from each bidder, per ad unit
pbjs.getAdserverTargeting()The key-values Prebid will send to Ad Manager
pbjs.getAllWinningBids()The bids that won and rendered
googletag.openConsole()Google's Publisher Console, to see which line item served

For a visual check, install Professor Prebid. Prebid describes it as "an open source Chrome extension to allow easy debugging and troubleshooting on publisher websites using Prebid.js." It shows ad units, bids, a timeline of each auction and your config on one screen.

Our pre-launch checklist

  • The page loads your own Prebid.js build, not the test CDN copy, and pbjs.version is the one you expect.
  • Every bidder returns bids on at least one slot. A bidder with zero bids usually has wrong parameters or is waiting on approval.
  • The hb_pb values in getAdserverTargeting() match line item rates in Ad Manager.
  • In the Publisher Console, a Prebid line item serves when its bid is the highest.
  • The ad renders at the right size with no blank box.
  • Most bids arrive inside the timeout. The timeline in Professor Prebid makes this easy to see.
  • Your ads.txt lists every bidder's lines. The IAB Tech Lab ads.txt page calls the file a way to "publicly declare the companies they authorize to sell their digital inventory."
  • With your CMP set to an EEA visitor, the consent string reaches the bidders.

Why Prebid bids don't win in Ad Manager

When bids come back but never serve, the problem is almost always in Ad Manager, not in Prebid. These are the causes we check, in this order.

  1. Buckets and line items don't match. The page uses dense while Ad Manager has medium line items, so a bid of $1.37 has no line item to target.
  2. Missing or inactive line items. A line item paused, archived or still waiting for approval can't serve.
  3. Wrong key names. The key in Ad Manager is hb_pb, but send all bids is on and the page sends hb_pb_bidderA instead.
  4. Sizes don't match. The bid is 300x600 but the line item only has 300x250 creatives.
  5. GPT called Ad Manager too early. disableInitialLoad is missing, so the ad request left before the bids came back.
  6. Something outranks the line items. A sponsorship or a standard line item at a higher priority takes the impression first.

Fix the first item on the list that applies, then test again. One change at a time makes it clear what worked.

Client-side Prebid.js or Prebid Server

Prebid.js runs the auction in the visitor's browser. Prebid Server runs it on a server and sends back the results. Most websites start with Prebid.js and move some bidders to Prebid Server later, once they have more bidders than the page can handle quickly.

The trade-off is simple. Each bidder in the browser adds network requests, which slows the page. Moving bidders to a server cuts those requests.

But some bidders get fewer user matches server-side, so their bids can drop. Test each bidder both ways before you move it for good. Our guide to DSPs and SSPs explains who's on the other end of these bid requests and what they check.

Keep your Prebid.js setup healthy after launch

Treat Prebid.js like any other software on your site: update it, watch it and prune it. A setup that worked in January can drift by summer.

  • Update the build a few times a year. Read the release notes first, because major versions remove old adapters and settings.
  • Review bidders each quarter. Drop the ones that rarely win and slow the auction. Remove their ads.txt lines too.
  • Watch timeouts by country and device. Mobile visitors on slow networks often need a different setting.
  • Check sellers.json for each SSP, so your seller ID matches your ads.txt. Our sellers.json explainer shows how.
  • Compare reports. Ad Manager's numbers and each SSP's numbers won't match exactly, but a big gap means a setup problem.

Frequently asked questions

Where do I download Prebid.js?

Download Prebid.js from the official builder at docs.prebid.org/download.html, where you choose the version, bid adapters and modules. Developers can also build it from the Prebid.js GitHub repository with gulp. Don't use the test file from Prebid's public CDN on a live site.

Is Prebid.js free?

Yes. Prebid.js is open source and free to use. You still need contracts with each bidder, an ad server such as Google Ad Manager, and someone to set it up and maintain it.

Can I use Prebid.js with AdSense?

No. Prebid passes bids as key-values that an ad server's line items target, and AdSense isn't an ad server. You need Google Ad Manager. AdSense and AdX demand can still compete in Ad Manager next to your Prebid bids.

How many line items do I need for Prebid?

One per price bucket for each set: 10 for low, 200 for medium, 170 for auto, 424 for dense and 2,000 for high granularity. Multiply by your bidders if you send all bids. Ad Manager 360 networks can use header bidding trafficking and skip line items.

What timeout should I use for Prebid?

Prebid doesn't set one right answer, and its docs show 3,000 ms only as an example. We start near 1,000 ms, then raise or lower it per device once Professor Prebid shows how fast your bidders really answer.

How do I know if Prebid.js is working?

Add pbjs_debug=true to a page URL and open the console. Run pbjs.getBidResponses() to see bids and pbjs.getAdserverTargeting() to see what goes to Ad Manager. Then use googletag.openConsole() to confirm a Prebid line item served.

Do I need a developer for the Prebid.js setup?

For the page side, yes, or at least someone comfortable editing your site's head code and testing in a browser console. The Ad Manager side is ad ops work. If you have neither, talk to MH AdX and we'll set it up with you.

Next step

Get one ad unit working with two bidders first, then grow from there. A small setup you can debug beats a big one you can't. If you'd rather have it built and tested for you, see our Prebid and header bidding setup.

Free tools

Is your site ready for Google AdX?

Check your AdX eligibility

Our current screening asks for $1,000 or more in two separate months of the last three, and invalid traffic under 10%.

Free AdX readiness checklist (PDF)

The 25 checks we run before recommending a site for AdX through MCM. Enter your details and download it straight away.

We will only use your email to reply about your site.

WhatsApp