AdTech

Anatomy of an OpenRTB Bid Request and Response

An annotated walkthrough of the fields that matter, the mistakes that cause no-bids and a checklist for validating real traffic.

By the Kensaltensi team · Last updated 27 October 2026 · 7 min read

OpenRTB is the protocol that lets an exchange or SSP describe an ad opportunity to many buyers, and lets those buyers answer in a standard way. It is a set of JSON objects exchanged over HTTP. Everything in programmatic advertising that you can observe, including bids, timeouts, price floors, deals and supply-chain checks, appears in these payloads. Being able to read them fluently is the fastest route to debugging an integration. This guide uses OpenRTB 2.6 and a realistic example; the full specification is maintained by IAB Tech Lab.

A bid request, annotated

Below is a simplified but realistic request for one banner impression on a website. All values are illustrative.

{
  "id": "5f2c9d1e-7a41-4b0c-9e2a-3d1b8a6c4f10",
  "at": 1,
  "tmax": 250,
  "cur": ["USD"],
  "imp": [{
    "id": "1",
    "tagid": "homepage-top",
    "secure": 1,
    "bidfloor": 0.85,
    "bidfloorcur": "USD",
    "banner": {
      "format": [{ "w": 300, "h": 250 }, { "w": 300, "h": 600 }],
      "pos": 1
    },
    "pmp": {
      "private_auction": 0,
      "deals": [{ "id": "DEAL-4821", "bidfloor": 2.50, "at": 1 }]
    }
  }],
  "site": {
    "id": "site-123",
    "domain": "publisher.example",
    "page": "https://publisher.example/news/story-slug",
    "publisher": { "id": "pub-456", "domain": "publisher.example" }
  },
  "device": {
    "ua": "Mozilla/5.0 (Linux; Android 14) ...",
    "ip": "203.0.113.42",
    "devicetype": 4,
    "os": "Android",
    "language": "en"
  },
  "user": {
    "buyeruid": "a1b2c3d4",
    "consent": "<TCF consent string>"
  },
  "regs": { "gdpr": 1, "gpp": "<GPP string>", "gpp_sid": [2] },
  "source": {
    "tid": "9d3b6e20-4f6a-43e0-8c2e-5b7f1f3d0a11",
    "schain": {
      "ver": "1.0",
      "complete": 1,
      "nodes": [{ "asi": "ssp.example", "sid": "1234", "hp": 1 }]
    }
  }
}

Read it from the top:

  • id uniquely identifies this auction. The response must echo it.
  • at is the auction type. A value of 1 means first-price: the winner pays their bid. A value of 2 means second-price plus.
  • tmax is the time in milliseconds the exchange will wait for a response, including network latency. Late responses are discarded, silently from the buyer's point of view.
  • cur lists the currencies the exchange accepts for bids.

The impression object

Each element of imp is one slot being offered. Its id is local to this request. The banner object lists acceptable sizes in format; a bid whose creative is not one of these sizes may be rejected. A slot can instead carry a video, audio or native object. bidfloor and bidfloorcur set the minimum price (a CPM, meaning cost per thousand impressions). secure: 1 requires HTTPS creative assets, which is the norm. The pmp object lists private-marketplace deals, each with a deal id that the buyer must reference in a response to claim deal pricing and terms.

Where and who: site, device, user

The site object (or app for mobile applications) describes the publisher, domain and page. device includes the user agent, IP address and device type, and is a key input for targeting and fraud detection. The user object may carry a buyer-specific identifier (buyeruid, usually produced through cookie or ID synchronisation) and the consent string.

Privacy and regulations: regs

In OpenRTB 2.6 the regulatory flags are first-class fields: regs.gdpr indicates whether European data-protection rules apply, regs.gpp carries a Global Privacy Platform string, and gpp_sid lists the applicable sections of that string. Buyers use these to decide whether they may bid and what data they may use. A missing or malformed consent signal is one of the most common reasons buyers decline to bid on otherwise good inventory.

Provenance: source and supply chain

The source.schain object records the path that the request has taken from the publisher to the buyer, with one node per intermediary. Each node names the seller's system (asi), its account identifier (sid) and whether it handles payment (hp). Buyers cross-check these nodes with the publisher's ads.txt and each seller's sellers.json to verify authorisation. See our ads.txt and sellers.json guide for how that verification works.

A bid response, annotated

{
  "id": "5f2c9d1e-7a41-4b0c-9e2a-3d1b8a6c4f10",
  "cur": "USD",
  "seatbid": [{
    "seat": "buyer-seat-77",
    "bid": [{
      "id": "bid-9001",
      "impid": "1",
      "price": 3.10,
      "dealid": "DEAL-4821",
      "adm": "<div>...creative markup...</div>",
      "adomain": ["advertiser.example"],
      "crid": "creative-2231",
      "w": 300,
      "h": 250,
      "mtype": 1,
      "nurl": "https://dsp.example/win?p=${AUCTION_PRICE}",
      "burl": "https://dsp.example/bill?p=${AUCTION_PRICE}"
    }]
  }]
}
  • id must equal the request id. A mismatch makes the exchange discard the response.
  • seatbid groups bids by buyer seat. Within each, bid objects reference the request's impression through impid.
  • price is the CPM bid. Under first-price rules, this is what would be charged on a win, so buyers apply bid shading to avoid overpaying.
  • dealid ties the bid to a deal from pmp.deals.
  • adm holds the creative markup (or a VAST document for video). Alternatively, it can be fetched from a URL.
  • adomain lists the advertiser domains, which exchanges use for brand-safety and blocking rules. crid identifies the creative for review and reporting.
  • mtype (new in 2.6) states the media type of the markup: 1 for banner, 2 for video, 3 for audio and 4 for native.
  • nurl and burl are the win and billing notice URLs. The macro ${AUCTION_PRICE} is replaced by the exchange with the clearing price before the call is made.

Saying no: no-bid responses

Most requests do not receive a bid, and that is expected. A buyer can simply return an empty HTTP 204 response, or a body that includes a no-bid reason code (nbr):

HTTP/1.1 204 No Content

-- or, with a reason, a 200 with a body like: --
{ "id": "5f2c9d1e-7a41-4b0c-9e2a-3d1b8a6c4f10", "nbr": 2 }

The specification defines numbered reason codes. A few of the most useful to recognise are 1 (technical error), 2 (invalid request), 3 (known web spider), 4 (suspected non-human traffic), 5 (cloud, data-centre or proxy IP), 7 (blocked publisher or site) and 8 (unmatched user). Later revisions add codes for ads.txt authorisation and supply-chain problems. Reason codes are optional, so absence of a code does not mean there was no reason, only that the buyer did not say.

The most common reasons a bid is rejected

SymptomLikely causeWhat to check
Response ignored entirelyid does not match the request, or invalid JSONEcho the request id exactly; validate against the schema
Bid droppedimpid not present in the requestUse the imp id supplied, not an internal id
Bid under floorPrice lower than bidfloor, or deal floor, in the stated currencyCompare after currency conversion; apply deal floors where relevant
Size not acceptedCreative w and h not in banner.formatReturn an allowed size, or set it explicitly in the bid
Late responseLatency above tmax, including network timeMeasure from the exchange perspective; reduce hops and payload size
Creative blockedMissing or disallowed adomain, category, or attributesAlways include advertiser domain; review exchange blocking rules
Deal not honouredMissing dealid, or deal not eligible for this buyer seatConfirm deal ID, seat and active dates match both sides
Markup mismatchmtype or adm format does not match what was requestedReturn VAST for video, HTML for banner, native JSON for native
Win notice never firesMacro not replaced, URL malformed, or mixed content (HTTP in HTTPS)Log the exact URL being called; ensure HTTPS and valid macros

Practical validation checklist

If you operate an exchange, SSP or DSP, or test an integration with one, these checks catch most problems early:

  1. Schema validation of every request and response against a JSON schema for the version in use, with sampling in production.
  2. Required-field audit for each partner. Partners often require fields that the specification marks optional, so keep their documentation alongside your tests.
  3. Id consistency tests: response id to request id, impid to imp id, deal id to PMP deals.
  4. Price tests around the floor: one cent below, exactly at, and above. Add currency-conversion cases.
  5. Format tests for each size, and for every media type you support.
  6. Privacy-signal tests: with and without consent, with malformed strings, and in regions with different rules.
  7. Timeout tests: responses just inside and just outside tmax, and slow DNS or TLS.
  8. Notice tests: win and billing URLs are called once, with the macro replaced, and tolerate retries without double counting.
  9. Traffic replay: capture a sample of real requests and replay them against a staging environment to compare behaviour before and after a change.

Versions and extensions

OpenRTB evolves through numbered revisions. Many deployments still run earlier versions, such as 2.5, where some of the fields above live in ext objects instead (for example source.ext.schain and user.ext.consent). Each exchange also defines its own extensions for features outside the core specification. When something does not behave as you expect, check which version both sides implement and where each puts the field in question, before assuming the field is missing.

Key takeaways

  • A bid request is an offer of one or more impressions with context; a bid response is a priced creative for a specific impression.
  • The ids must line up: response id equals request id, and each bid impid equals an imp id from the request.
  • Prices are CPM in the stated currency, and they are checked against floors, formats and deal terms before they can win.
  • Privacy and supply-chain objects are first-class fields in 2.6 and often decide whether a buyer will bid at all.
  • Debug with real payloads: compare what was sent against the spec and against what the partner documents.

Related guides

Further reading

About this guide. Written by the Kensaltensi engineering and QA team for educational purposes. Examples are illustrative, and standards evolve, so check the primary sources above before relying on a detail in production. If you spot an error or an out-of-date statement, email hello@kensaltensi.org and we will review and correct it.