Guides

OpenRTB loss reason codes (lurl)

When a bid loses, the exchange can call the bid's lurl loss notice and substitute a Loss Reason Code into the ${AUCTION_LOSS} macro: 102 Lost to Higher Bid, 100 Below Auction Floor, the 200-range creative filters, and the rest. The full table is below, along with how the notice works and how to read the ranges when you are debugging a falling win rate.

How a loss notice works

A bidder that wants loss telemetry puts a loss notice URL in bid.lurl, with macros where the facts should go:

{
  "id": "1",
  "impid": "imp-1",
  "price": 9.43,
  "lurl": "https://dsp.example.com/loss?auction=${AUCTION_ID}&reason=${AUCTION_LOSS}&mtw=${AUCTION_MIN_TO_WIN}",
  "adm": "..."
}

If the bid loses and the exchange supports loss notices, it expands the macros and calls the URL: ${AUCTION_LOSS} becomes the reason code, ${AUCTION_PRICE} is only meaningful on wins, and exchanges that support ${AUCTION_MIN_TO_WIN} fill in the price that would have turned the loss into a win. The macro reference covers the full substitution table.

Three caveats before you build dashboards on this. Loss notices are optional, so absence of a notice is not evidence of a win. Exchanges differ on which codes they send and when (some batch, some sample, some only send economic losses). And the code list itself lives in the OpenRTB 3.0 document, which is where 2.6 points for both this list and the no-bid reason codes; the values below come from that list.

The loss reason code table

ValueNameMeaning
0Bid WonNot a loss at all; exists so one notice pipeline can report every bid outcome.
1Internal ErrorSomething failed inside the exchange while handling the bid.
2Impression Opportunity ExpiredThe auction or impression window closed before the bid could be used.
3Invalid Bid ResponseThe response failed the exchange's parsing or validation.
4Invalid Deal IDThe dealid on the bid did not match any deal known to the exchange.
5Invalid Auction IDThe bid's id did not match the request id of a live auction.
6Invalid Advertiser DomainThe adomain was missing, malformed, or not allowed.
7Missing MarkupNo adm and no way to resolve markup for a bid that needed it.
8Missing Creative IDThe crid was absent and the exchange requires it.
9Missing Bid PriceNo price on the bid object.
10Missing Minimum Creative Approval DataThe exchange needed creative approval attributes that were not supplied.
100Bid was Below Auction FloorThe bid did not clear bidfloor for the impression.
101Bid was Below Deal FloorThe bid referenced a deal but came in under that deal's floor.
102Lost to Higher BidStraight economic loss; someone paid more.
103Lost to a Bid for a DealA deal-backed bid took priority over this open-auction bid.
104Buyer Seat BlockedThe publisher or exchange blocks this seat on this inventory.
200Creative Filtered - General; Reason UnknownThe creative was filtered and the exchange is not saying why.
201Creative Filtered - Pending Processing by ExchangeThe creative is still in scanning or approval and cannot serve yet.
202Creative Filtered - Disapproved by ExchangeThe creative was reviewed and rejected.
203Creative Filtered - Size Not AllowedCreative dimensions did not fit the impression.
204Creative Filtered - Incorrect Creative FormatWrong media type or format for the slot (for example, video markup in a banner slot).
205Creative Filtered - Advertiser ExclusionsThe advertiser is on a publisher or deal block list.
206Creative Filtered - App Store ID ExclusionsThe promoted app's store ID is excluded.
207Creative Filtered - Not SecureThe creative loads http resources into an https context.
208Creative Filtered - Language ExclusionsCreative language is excluded for this inventory.
209Creative Filtered - Category ExclusionsThe creative's category hits bcat or a deal's category blocks.
210Creative Filtered - Creative Attribute ExclusionsA creative attribute (battr) is blocked, such as auto-play or expandable.
211Creative Filtered - Ad Type ExclusionsThe ad type is not accepted on this placement.
212Creative Filtered - Animation Too LongAnimation exceeds the publisher's duration limit.
213Creative Filtered - Not Allowed in DealThe creative violates the terms of the deal it bid into.
214Creative Filtered - Invalid SKAdNetworkThe SKAdNetwork signature or fields failed validation.
215Creative Filtered - App Bundle ExclusionsThe promoted app bundle is excluded.
500+Exchange-specificPrivate values; the spec says to communicate them with buyers beforehand.

Reading the ranges

The list is organized in blocks, and the block tells you who owns the fix:

  • 1-10: your response is broken. These are hygiene failures the exchange found in the bid itself: unparseable response, missing price, missing markup, a dealid that does not exist. Every one of these is fixable unilaterally, and most are visible in the response before it leaves your servers. The bid response anatomy page lists what a well-formed bid carries.
  • 100-104: auction economics. Floors, higher bids, deal priority, seat blocks. A spike in 100 or 101 means your pricing model and the floor signals disagree; a spike in 103 means open-auction bids are losing to deals and the inventory you want has moved behind PMP.
  • 200-215: creative filtering. The bid was fine; the creative was not. Size, format, security, category, attributes, app bundle. These are the codes worth alerting on, because they are systematic: a creative that trips 207 (Not Secure) or 203 (Size Not Allowed) will lose every auction it enters until someone fixes the creative or the targeting.
  • 500 and up: exchange-specific. Meaningless without the exchange's documentation. If a partner sends them, get the mapping in writing.

Debugging with loss codes

  1. Separate the ranges first. A falling win rate from 102 is a pricing problem; the same fall from 200-range codes is an ops problem. Aggregating them into one loss metric hides both.
  2. Treat 3, 7, 8, 9 as build failures. They mean the exchange received something malformed. Validate the exact response you send: the tester accepts bid responses as well as requests, and flags missing required fields and type mismatches against the spec.
  3. Cross-check 4 (Invalid Deal ID) against your deal sync. It usually means a deal was paused or renamed on the exchange side while your bidder kept bidding into it.
  4. Use min-to-win where you can get it. In first-price auctions, ${AUCTION_MIN_TO_WIN} on losses is the cleanest shading signal the protocol offers; it turns 102 from a verdict into a calibration point. See the first-price vs second-price guide for how shading fits in.

FAQ

Is the loss notice (lurl) guaranteed to fire?

No. lurl is optional on both sides: a bidder may omit it, and an exchange is not obligated to call it or to support every loss reason. Support and semantics are an integration-level agreement. If loss telemetry matters to your bidding, confirm with each exchange which codes it actually sends.

What is the difference between loss reason codes and no-bid reason codes (nbr)?

Direction. nbr flows from bidder to exchange and explains why the bidder declined to bid at all. Loss reason codes flow from exchange to bidder and explain why a bid that was made did not win. Both lists live in the OpenRTB 3.0 document, but they are different lists with overlapping numbers, so label them clearly in logs.

Is loss reason 102 related to VAST error 102?

No, coincidence. OpenRTB loss reason 102 means Lost to Higher Bid. VAST error 102 means the player does not support the VAST version of the ad response. They live in different specs at different layers of the stack.

What is AUCTION_MIN_TO_WIN?

A substitution macro that expands to the minimum price the bid would have needed to win (or, on a win, to keep winning). Exchanges that support it, notably Google's exchange, expose it in loss and billing notices so bidders can calibrate bid shading in first-price auctions without guessing.

Validate the bid before the exchange grades it

Codes 1 through 10 are the exchange telling you your response failed validation. rtblint runs the same class of checks locally: paste a bid response into the tester or run rtblint validate response.json via the CLI to catch missing prices, absent markup, and malformed fields before an exchange turns them into loss codes.