amBrain

RTB bidder development: the bid path, the deadline and the tail

Published Sep 23, 2026Facts checked: Sep 23, 2026

Short answer

An RTB bidder receives bid requests at a rate the exchanges choose, decides whether and what to bid, and must answer inside a deadline that includes the network. A bidder built for that keeps connections alive, drops requests it will never buy before doing real work, finds eligible campaigns through an index rather than a scan, keeps budget and frequency checks local, answers a fast no-bid when it cannot finish, and measures p99 per exchange connection. Rust or C++ removes collector pauses from the bid path; the network, the design and the measurement still decide the tail.

On this page

What happens to a bid request inside the bidder?

Steps of a bid request inside the bidder and where each one spends the deadline
StepWhat happensWhere time is lost
1. ConnectionThe request arrives on a persistent connectionA lapsed keep-alive forces a new TLS handshake inside the auction window
2. AdmissionRead tmax, compare it with the current queue delayWork started on a request that cannot finish in time still costs CPU
3. DecodeRead only the fields the bidder usesBuilding a full object graph for every request
4. Pre-filterDrop requests blocked by category, advertiser or floorEvaluating campaigns for requests that could never win
5. Candidate selectionLook up eligible campaigns in an index keyed by targeting attributesScanning every campaign on every request
6. Budget and frequencyCheck local counters synchronised in the backgroundA remote call per request on the hot path
7. PricingRules or a model produce the bid priceModel inference without its own deadline and fallback price
8. ResponseSerialise the bid with markup or notice URLsAllocation and copying at the boundary
9. NoticesWin, billing and loss notices processed off the bid pathMixing notice handling into the request threads

Several of these steps are defined by the protocol. OpenRTB's best practice reads: "One of the simplest and most effective ways of improving connection performance is to enable HTTP Persistent Connections, also known as Keep-Alive"[1]. The request carries the filters for step 4: bcat, "Blocked advertiser categories using the specified category taxonomy"; badv, a "Block list of advertisers by their domains"; and bidfloor, the "Minimum bid for this impression expressed in CPM"[1]. A no-bid can be "an empty response with HTTP 204"[1]. The win notice URL is called "if the bid wins (not necessarily indicative of a delivered, viewed, or billable ad)", which is why spend is counted on the separate billing notice[1].

How much of the deadline does the bidder actually get?

OpenRTB defines tmax as the "Maximum time in milliseconds the exchange allows for bids to be received including Internet latency to avoid timeout"[1]. The bidder's own budget is what is left after the round trip.

On Google's Authorized Buyers, "The deadline typically ranges from 80 to 1000 ms"[2].

Google states: "We require that 85 percent of responses be received within the deadline from the perspective of the trading location and will throttle bidders that cannot consistently achieve this"[2].

Google recommends "targeting a total time well below the deadline" to leave a buffer for changes in network latency between the bidder and the trading location, and lists its trading locations as Northern Virginia, the San Francisco Bay Area, Amsterdam and Singapore[2].

In practice this means one internal deadline per exchange connection, derived from that connection's measured round trip, and admission control that answers a no-bid when the queue already makes the deadline impossible. A fast no-bid counts as an answer; a late bid counts as a timeout.

How is capacity planned?

  • The request rate sets the bill. Servers and bandwidth scale with every request answered, including the auctions you lose. Pre-filtering is the first capacity lever.
  • Stateless bidders, replicated state. Bidder instances behind a load balancer hold read-only campaign indexes and local counters; budgets and frequency are reconciled in the background.
  • Regions follow supply. A bidder near the trading location spends less of the deadline on the wire[2].
  • Shed load deliberately. Under overload, answering no-bid early is cheaper than timing out, and repeated timeouts invite throttling[2].
  • Measure per core with your own traffic. Throughput depends on request size, campaign count and pricing work; a figure measured on someone else's workload does not transfer.

How is the tail measured?

  • Per exchange connection, not per fleet. A timeout problem usually shows on the connection with the tightest tmax and the heaviest requests first.
  • Split the time. Handler time, time waiting to be scheduled, and time on the wire each have different fixes; Go GC pauses in an RTB bidder shows how to separate them.
  • Open-loop load. A generator that waits for replies stops sending during a stall and hides it; send at a fixed rate and count latency from the intended send time.
  • Percentiles, not averages. p99 and p99.9 per connection, checked against that connection's internal deadline.

Which language for the bid path?

Language choices for the bid path and what each trades
OptionWhat it removesWhat it keeps or adds
RustGarbage-collection pauses; data races in shared state are caught at compile timeAllocator behaviour, scheduling, network and design still set the tail
C++Garbage-collection pausesMemory-safety bugs are found by review and tooling, not the compiler
Go, tunedNothing structural; allocation rate, live heap and runtime settings reduce collector costA collector that belongs to the whole process
JVM, tunedCollector choice lowers pauses at a memory costTuning per collector and per heap size

A rewrite pays when the measured milliseconds are in the handler and the collector; it returns nothing when they are on the wire or in the scheduler. Moving the smallest piece that owns the allocations, candidate selection, targeting or pricing, is often enough.

Start from open source or from a bidder-as-a-service?

RTB4FREE describes its bidder as "The OpenRTB 2.0 compliant bidder for RTB4FREE, the open source bidder / DSP"; it is written in Java under Apache-2.0, and its repository was last pushed on 16 November 2022[3].

Beeswax, described by AdExchanger in December 2020 as "the 'bidder-as-a-service'" when FreeWheel bought it, was a product where "users can install their own algorithms"[4].

An open-source bidder is a reading reference and a test harness more than a starting point when it is no longer maintained. A bidder-as-a-service keeps infrastructure rented and puts your logic inside it. A bidder of your own makes sense when the logic, the data and the infrastructure cost are all yours to change; the rest of the platform around it is on DSP development company, and the rented DSPs are compared on white-label DSP vs own DSP.

How does a bidder build or rebuild run?

  1. 1.Measure first. Per-exchange timeout rates, tmax distributions and a timing split of the current bidder, if there is one.
  2. 2.Design the budget. Internal deadline per connection, admission rule, what runs on the bid path and what runs beside it.
  3. 3.Build against recorded traffic. A replay of real requests at a fixed rate is the acceptance test from the first week.
  4. 4.Shadow. The new bidder receives mirrored traffic on separate instances and its decisions are compared with the old one's, without bidding.
  5. 5.Ramp by connection. One exchange connection at a time, with automatic rollback on a timeout threshold agreed in advance.

What should you ask an RTB bidder developer?

  1. 1.Which bidder of yours is live, at what request rates, and on which exchanges?
  2. 2.Before proposing a language, how will you find where the milliseconds go today?
  3. 3.Which load generator do you use, and does it correct for coordinated omission?
  4. 4.What is the acceptance criterion: which connection, which percentile, what margin below tmax?
  5. 5.Who is on call for the bid path after launch?
  6. 6.What do we receive at the end, and does anything stay yours?

Who should not build a custom bidder?

  • Buyers without their own supply connections; a DSP seat covers them.
  • Teams whose timeouts come from geography rather than code: moving the bidder closer to the exchange is cheaper than rewriting it[2].
  • Anyone who cannot staff the bid path after launch. A bidder nobody watches drifts out of spec as exchanges change theirs.

About amBrain

  • amBrain is a Yerevan, Armenia software engineering company building low latency trading platforms, matching engines, and real-time bidding systems in Rust.
  • DSP development, real-time bidding platforms, and ad exchange engineering.
  • amBrain builds ML inference inside the bidder: the model decides the bid within the auction window.
  • amBrain builds event analytics pipelines for ad tech: collection, processing and reporting of impression and click events.
  • amBrain diagnoses slow systems in trading, betting and ad tech: the running platform is measured end to end and the report names where the time goes.
  • Three formats: full delivery, a dedicated team, or engineers embedded in your team.
  • The client keeps full ownership of the product and the code, except our reusable components.

Related on this site: DSP case study and real-time bidding infrastructure.

Frequently asked questions

The service in a DSP that receives bid requests from exchanges, decides whether and how much to bid for each impression, and answers before the exchange's deadline. Campaign tools, reporting and billing sit around it.

Inside the request's tmax, which includes network time in both directions[1]. On Google's Authorized Buyers the deadline typically ranges from 80 to 1,000 ms, and 85 percent of responses must arrive in time[2].

Because the exchange judges each response, not the average. A tail on one connection, from a collector, a queue, a lapsed keep-alive or distance, shows up as timeouts long before it moves the mean.

Rust removes collector pauses from the bid path, which matters when the measured tail is in the handler. If the time is lost on the wire or in scheduling, a rewrite in any language returns little; measure the split first.

Yes: run the new bidder on mirrored traffic in shadow mode, compare decisions, then move one exchange connection at a time with an automatic rollback threshold.

Product and company names are trademarks of their respective owners and are used only to identify their products. No vendor named here reviewed or endorsed this page.

Sources

  1. [1]IAB Tech Lab, OpenRTB 2.6 specification (keep-alive, bcat, badv, bidfloor, tmax, no-bid responses, win and billing notices). Specification · checked Sep 23, 2026
  2. [2]Google, Authorized Buyers Real-time Bidding: peer guide (deadline range, the 85 percent rule, buffer advice, trading locations). Official documentation · checked Sep 23, 2026
  3. [3]GitHub (RTB4FREE), RTB4FREE/bidder repository metadata (description, language, licence and date of the last push). Official documentation · checked Sep 23, 2026
  4. [4]AdExchanger, FreeWheel Buys Beeswax (bidder-as-a-service description), Dec 17, 2020. Press · checked Sep 23, 2026

Free project intro call, 30 minutes.

We reply within 24 hours.

Book a Call