A browser can realistically run an auction against roughly five to twelve demand partners before page speed and viewability start to degrade, and every bidder you add past that point costs you measurable performance. That single constraint explains most of the client-side versus server-side debate. The auction mechanism is identical in both cases: demand partners receive a request, they respond with a CPM bid, and the highest bid competes in the ad server. What changes is where the auction runs, in the user's browser or on a remote server, and that change ripples through latency, cookie match rates, demand reach and operational control.
We run both models across our publisher base and we combine them on most large sites, so this article reflects what we see in production rather than vendor positioning. The short version: client-side header bidding gives you maximum bid transparency and the best cookie pass-through, server-side header bidding gives you access to more demand without the latency tax, and the correct answer for almost any serious publisher is a deliberate split between the two. The long version, including which inventory belongs on which side and how we configure the hybrid, follows.
How client-side header bidding works
In client-side header bidding, the auction runs in JavaScript inside the user's browser. The typical implementation loads Prebid.js on the page, and Prebid.js fires bid requests in parallel to every configured bidder adapter. Each bidder responds with a CPM, Prebid.js identifies the winning bid per slot, and it passes that price into the ad server through a key-value targeting call. The ad server then runs its own auction, comparing the header bidding winner against reservation campaigns and any other demand lined up against the same slot.
The strength of this model is transparency and control. Every bid response lands in the browser, so you can inspect it, log it and debug it directly. You see each bidder's CPM, their creative specification, their deal ID if they bid through one, and their latency profile. This visibility matters operationally. When a bidder starts timing out or returns junk creatives, you find out fast and you can act on it.
The second strength is cookie quality. Because the bid request originates from the user's browser, first-party cookies and any identity signals the browser still permits travel with the request to each bidder. Bidder-side user matching, where it exists, happens against cookies set in that same browser context. This is why client-side bids typically clear at higher CPMs for the same impression: the buyer can recognize the user, frequency-cap them, and price them accordingly.
The weakness is the ceiling on bidder count. Each bidder adds JavaScript weight, network round trips and CPU work to the page. Past roughly ten to twelve adapters, timeout rates climb, the header auction starts delaying the ad server call, and viewability drops because creatives render late. Publishers respond by shortening timeouts, which then causes the slowest bidders to drop out entirely. You end up rationing demand slots, and the bidders that lose those slots are the ones that would have paid most for your specific audience.
How server-side header bidding works
In server-side header bidding, the browser makes one call to an external auction server, and that server fans the request out to dozens of demand partners on the server side. The Prebid Server overview describes this as open-source server-to-server header bidding with more than 230 server-side adapters available, which is an order of magnitude more demand than any client-side wrapper can carry. The server collects the bids, picks the winner, and returns a single consolidated response to the page, which then passes the top bid into the ad server as usual.
The immediate benefit is page weight. The browser executes one call instead of ten, and the fan-out happens on infrastructure built for parallel request handling. You can add demand partners without adding per-partner latency to the page, which removes the rationing problem entirely. For publishers with heavy pages, mobile traffic or strict Core Web Vitals targets, this is often the deciding factor.
The costs are subtler. First, cookie match rates drop. The bid request now originates from the auction server's domain, not the user's browser, so bidders must rely on server-side user syncs. Sync coverage varies by bidder and by region, and in practice some server-side bids come in as untargeted or lightly targeted inventory buys, which prices lower. Second, you lose per-bid visibility unless your server-side provider exposes full bid-level reporting. Some do, some only report the winning bid, and opaque reporting makes debugging and partner evaluation harder. Third, you add a dependency: if the auction server has an outage or a slow region, every downstream bidder disappears at once instead of one adapter failing independently.
There is also a variant worth naming because it comes bundled with major ad serving contracts. Google's Open Bidding runs the server-side auction inside Ad Manager, and per Google Open Bidding requirements it ships with Ad Manager 360 contracts and each demand source needs a separate agreement. It is a legitimate server-side demand channel, but it is a closed one: you cannot inspect individual bids, the auction logic is not yours to configure, and access depends on your contract tier. We treat Open Bidding as one demand input among many rather than as a replacement for a header bidding stack you control.

Where the trade-space actually sits
The real decision variables are four, and it helps to state them plainly because most vendor marketing only discusses one.
Latency is the first. Client-side latency scales with bidder count; server-side latency stays roughly flat as you add partners because the fan-out happens off-page. If your pages are already heavy, or if mobile users dominate, the server side wins on this axis.
Identity is the second. Client-side requests carry the browser's cookie context; server-side requests depend on pre-established user syncs. In geographies and browser environments where sync coverage is strong, the gap is small. Where third-party cookies are blocked or syncs are thin, server-side bids lose user recognition and price down accordingly. This is why the same inventory can perform differently on the two sides, and why you should test rather than assume.
Transparency is the third. Client-side gives you every bid in the browser console and in your own logs. Server-side transparency depends entirely on what your auction provider reports back. For publishers who negotiate direct deals and need bid-level evidence of what agencies paid, this axis often decides the question on its own.
Demand reach is the fourth. Server-side reaches partners that cannot or will not build a client-side adapter: bidders with heavy integrations, regional exchanges, and demand sources that only speak server-to-server. Client-side reaches the partners with mature browser adapters, which in many markets are also the ones with the strongest buyer relationships. Reach and price do not always point the same direction.
Notice that none of these variables is "which one is better." The question is which inventory, in which environment, against which demand, should run where. That is how we approach it when we onboard a publisher, and it is how the rest of this article proceeds.
Which inventory belongs on which side
A practical allocation model looks like this, and we use a version of it when we configure header bidding options for a new publisher.
Desktop web inventory with strong first-party cookie coverage belongs client-side first. This is where cookie pass-through pays the most, where browsers still tolerate parallel requests, and where the premium demand, the agency deals and the brand budgets, expects user-level targeting. Start client-side, load your highest-paying partners there, and monitor timeout rates per bidder.
Mobile web inventory is a split decision. If the page is lean and the timeout budget holds, client-side still wins on price for the top three to five partners. If the page is heavy or mobile connection quality varies across your audience, move the long tail of demand server-side and keep only the fastest, highest-paying partners in the browser. Mobile users punish slow ad calls with bounces, and a bounced user generates zero revenue regardless of bid density.
In-app inventory belongs server-side by default. There is no browser cookie context to preserve inside an app, the client-side identity advantage largely disappears, and app frameworks are far more sensitive to main-thread work than desktop pages. Server-side adapters also handle app-specific protocols and mediation setups more cleanly. The one caveat: verify that your server-side provider reports bid-level data back to you, because in-app debugging without it is painful.
CTV and OTT inventory belongs server-side almost without exception. Server-side ad insertion exists precisely because smart TV environments cannot execute browser auctions, VAST tags must be stitched server-side into the content stream, and the demand sources for CTV, the agencies buying programmatic TV, all transact server-to-server. If you operate connected TV inventory, the client-side question does not arise.
High-value direct deal inventory deserves special treatment. When an agency has committed budget against your audience, you want that demand in the auction where you can verify it: bid logs, deal ID matching, and clear evidence that the deal bid at its floor. We run direct deals from global and local brand agencies through our WireAds SSP, and we push them into the same unified auction as open market demand so they bid highest against your ad spaces. Where verification requirements are strict, we keep the deal traffic on the path with full bid visibility.
The hybrid setup and how to configure it
The hybrid model is not a compromise; it is the configuration that most large publishers converge on. The mechanism is well established: the s2sConfig in Prebid.js splits bidders between the browser auction and the server auction, and the Prebid.js documentation on combining Prebid.js with Prebid Server covers exactly this pattern. The browser runs its own adapters for a short list of partners, simultaneously sends one consolidated request to the server for the rest, and merges both result sets before passing the top bid to the ad server.
The configuration sequence looks like this in practice:
- Rank your demand partners by revenue over the last 60 to 90 days, and note each partner's median bid latency.
- Put the top performers with acceptable latency into the client-side wrapper, typically three to eight partners depending on page weight.
- Put the remaining partners, plus any new partners you want to test, on the server side.
- Set the client-side timeout to your actual budget, commonly 800 to 1200 milliseconds on desktop and lower on mobile, and align the server-side timeout inside that window.
- Pass both result sets into the ad server and let the unified auction pick the winner per slot.
The key discipline is step 4. Many hybrid implementations fail because the server-side response arrives after the client-side timeout has already fired, so the server demand never actually competes. The server-side window must fit inside the client-side window, with margin for the ad server call itself. We audit this timing on every implementation we take on, and it is the single most common fix we apply to underperforming stacks.
The second discipline is periodic rebalancing. Demand performance shifts, adapters improve or degrade, and new partners enter. Review the split quarterly: promote server-side partners that consistently win into the client-side list if latency permits, and demote client-side partners that time out or underbid into the server-side pool. The split is a tuning parameter, not a one-time decision.
Our own Prebid integration follows this hybrid shape. We combine Prebid, OpenRTB, Google MCM and Google AdX demand together with direct deals in one auction, so every demand source bids against your inventory simultaneously instead of fragmenting into separate calls. Because we work CPM-based and pay Net 30, the reporting side stays predictable while you tune the technical side, and our demand filtering removes the low-quality creatives that otherwise erode viewability and trust.
Measuring whether your split is right
Three metrics tell you whether the allocation is working, and you should trend all three rather than glance at any single day.
Overall revenue per thousand impressions, broken out by platform, is the headline number. Compare it against a pre-hybrid baseline over a full week minimum, because day-of-week effects swamp shorter windows.
Timeout rate per partner is the health metric. A client-side partner timing out above roughly 10 to 15 percent of requests is not really participating; it is consuming your timeout budget and returning nothing. Move it server-side or drop it. A server-side partner with high no-bid rates is either missing user syncs or your inventory does not fit its buyers, and the fix differs depending on which.
Bid density, meaning the number of distinct bids per impression across both sides of the auction, is the competition metric. Rising revenue with flat bid density usually means your existing winners are paying more, which is fine but fragile. Rising bid density with flat revenue means new partners are bidding but losing, which is also fine, they sharpen the auction. Falling bid density is the warning sign: demand is dropping out and revenue will follow.
Where your stack supports it, run a controlled split test: shift one or two partners across the boundary, hold everything else constant, and measure over a week. Anecdotal same-day comparisons between client-side and server-side revenue mislead constantly, because the two paths see different user sync coverage and different buyer pools for the same impression.
Common implementation mistakes
We see the same failure patterns repeatedly, and they are all avoidable.
Running the full server-side response on a separate, later ad server call defeats the purpose. If the server-side winner only competes when the client-side auction produced nothing, you have built a fallback, not a unified auction, and your server demand never pushes prices up. Merge both result sets before the ad server call.
Ignoring user sync configuration on the server side quietly costs revenue. Server-side bidders only recognize users whose syncs were established, and sync setup is part of implementation, not an optional extra. Verify sync coverage per partner at launch and after any major browser privacy change.
Leaving the client-side wrapper static for a year is a slow leak. Partners degrade, timeouts creep up, and the split that was optimal at launch becomes a liability. Put the quarterly rebalance on the calendar as an operational task with an owner.
Finally, do not treat the choice as permanent or ideological. Client-side maximizes identity pass-through and transparency, server-side maximizes reach and page speed, and hybrid captures both at the cost of slightly more configuration work. That work is routine for an ad operations team, and the payoff shows up as higher competition per impression across every platform you monetize, web, app and CTV alike. If your current setup runs everything on one side of the line, the most valuable next step is a measured migration of the inventory that the other side serves better.


