What it is, and why it matters
In a real-time programmatic auction (RTB), everything starts with a bid request. When a user loads a web page, the publisher's SSP (Supply-Side Platform) has less than 100 milliseconds to assemble a JSON object describing the available inventory and send it to dozens of DSPs simultaneously. Each DSP reads that JSON, decides whether it wants to bid and at what price, and responds with a bid response. All of this happens before the page finishes rendering.
The standard that defines the structure of this JSON is called OpenRTB, maintained by the IAB Tech Lab. Version 2.5 is still the most widely deployed in production; 2.6 is gaining traction, especially for native supply chain support and new privacy regulations.
The overall structure
An OpenRTB 2.x bid request is a JSON object with a few root fields and nested objects. The spec distinguishes required, recommended, and optional fields. In practice, SSPs send far more than the minimum — that's what enables DSPs to target precisely.
"id": "e3d9a3f2-7b1c-4e2a...", // unique identifier for this request "at": 1, // auction type: 1=first price, 2=second price "tmax": 350, // max response time in ms "cur": ["EUR"], // accepted currencies "imp": [...], // array of available impressions "site": {...}, // publisher context (OR "app") "device": {...}, // user's device "user": {...}, // user data + consent "regs": {...}, // regulatory framework (GDPR, CCPA, GPP) "source": {...}, // inventory origin + schain "ext": {...} // SSP proprietary extensions
| Object | Required? | Role |
|---|---|---|
| imp[] | Yes (min. 1) | Description of the ad slot being sold |
| site OR app | Yes (one of the two) | Publisher context — website or mobile app |
| id | Yes | Unique request identifier (for log reconciliation) |
| device | Recommended | Device, OS, IP, geolocation |
| user | Recommended | User identity, TCF consent, EIDs |
| regs | Recommended | Regulatory flags (GDPR, COPPA, US Privacy) |
| at | Optional | Auction type (default = 2, second price) |
| tmax | Optional | Timeout in ms (no default — the DSP applies its own) |
The imp object — the heart of the auction
The imp (impression) object describes exactly what the SSP is selling. A bid request can contain multiple impressions (for example, all ad slots on a page), but in practice most requests contain only one.
{
"id": "1",
"banner": {
"format": [
{"w":300,"h":250},
{"w":320,"h":50}
],
"pos": 1, // 1 = above the fold
"api": [3, 5] // MRAID-1 and MRAID-2 supported
},
"bidfloor": 1.80, // floor CPM in EUR
"bidfloorcur": "EUR",
"secure": 1, // HTTPS required for the creative
"tagid": "slot_hp_sidebar",
"pmp": {
"private_auction": 0, // 0 = open + deals, 1 = deals only
"deals": [{
"id": "DEAL-PREMIUM-007",
"bidfloor": 4.50, // deal-specific floor
"at": 1, // first price for this deal
"wseat": ["dsp-seat-42"] // authorized buyer
}]
}
}Impression formats
The imp object contains not multiple but exactly one format sub-object at a time — banner, video, audio, or native. Video-focused DSPs filter out requests without a video object as soon as they receive them, before even reading the other fields.
| Format | Key fields | Notes |
|---|---|---|
| banner | format[], pos, api | Multiple sizes possible in format |
| video | protocols[], minduration, maxduration, placement | protocols lists supported VAST standards |
| audio | protocols[], minduration, maxduration | Based on DAAST — rarely used outside podcast/radio |
| native | request (JSON in a string) | IAB Native 1.2 spec encoded as a JSON string |
Bidfloor and PMP deals
The bidfloor is the minimum CPM the SSP will accept. Any bid below it is automatically rejected. If bidfloorcur is absent, the assumed currency is USD — a frequent source of confusion when the DSP bids in EUR.
The pmp (Private Marketplace) object defines negotiated deals between a publisher and a specific buyer. When private_auction = 1, only buyers listed in the deals can participate. When it equals 0, deals coexist with the open auction — an authorized buyer can bid on the deal (floor at €4.50) or in the open auction (floor at €1.80).
Device and User — targeting and privacy
These are the two objects DSPs scrutinize most closely when making a buying decision. They're also the most sensitive from a GDPR perspective.
The device object
It describes the device displaying the ad. The ifa (Identifier for Advertising) field is the IDFA on iOS or the GAID on Android — the mobile advertising identifier that enables retargeting and conversion measurement. Since iOS 14.5, collecting it requires explicit user consent via ATT.
device.ip) is personal data under GDPR. Many SSPs truncate it to 3 octets before sending (92.184.xxx.0) or hash it. DSPs that use the IP for geographic inference must ensure the processing is covered by the TCF consent string.
The user object and the TCF consent string
This is where user consent flows. The user.consent field contains the TCF 2.x consent string encoded in Base64url — a string that summarizes the user's choices on the publisher's cookie banner.
{
"id": "u_8f3a2e1d9c7b", // exchange-specific ID
"buyeruid": "dsp_uid_4499xk", // mapped ID on the DSP side (cookie sync)
"consent": "CPziCYAP...", // TCF 2.x consent string
"eids": [
{
"source": "uidapi.com", // UID 2.0 (The Trade Desk)
"uids": [{ "id": "AgAAAAVacu7...", "atype": 3 }]
},
{
"source": "liveramp.com", // RampID
"uids": [{ "id": "XY7mRIqaqBz...", "atype": 3 }]
}
]
}Extended IDs (eids) are the industry's response to the end of third-party cookies. They carry standardized alternative identifiers — UID 2.0, LiveRamp's RampID, ID5, PubCommonID — directly in the bid request, without relying on cookies.
The regs object — law in JSON
This is the regulatory field. A DSP that doesn't read it correctly risks processing data without a legal basis — a major legal exposure in Europe.
{
"gdpr": 1, // 1 = subject to GDPR
"ext": {
"us_privacy": "1---", // CCPA string (1=applicable, ---=no opt-out)
"gpp": "DBAA", // Global Privacy Platform string
"gpp_sid": [2] // applicable GPP section (2=California CPRA)
}
}regs.gdpr = 1 and user.consent is absent, the DSP cannot determine which purposes were consented to. Most GDPR-compliant DSPs won't bid in that case, or will bid contextually only without using user data. This is a frequent cause of low fill rates on European traffic.
Supply Chain — tracing inventory origin
The schain (Supply Chain Object) is one of the major advances in OpenRTB 2.6. It lists every intermediary that touched the inventory between the publisher and the DSP — much like a cargo manifest tracing a shipment's route.
{
"ver": "1.0",
"complete": 1, // 1 = complete chain from A to Z
"nodes": [
{
"asi": "exchange-premium.com", // SSP domain
"sid": "pub-4829", // publisher ID on this SSP
"rid": "req-e3d9", // request ID
"hp": 1 // 1 = authorized to sell this inventory
},
{
"asi": "monsiteactu.fr",
"sid": "site_001",
"hp": 1
}
]
}The complete = 1 field is crucial: it indicates the chain is complete from the direct seller to the DSP. A complete = 0 means there may be undeclared intermediaries — a red flag for brand safety and ad fraud prevention.
The 6 most common bid request errors
| Error | Impact | Fix |
|---|---|---|
| GDPR=1 without user.consent | DSP doesn't bid or bids without targeting | Ensure the CMP passes the consent string before the bid request |
| bidfloor without bidfloorcur | Currency ambiguity, potential underbidding | Always specify bidfloorcur |
| tmax too short (<150ms) | DSP-side timeouts, low fill rate | 300–500ms is the standard range for most SSPs |
| site AND app both present | Undefined behavior on the DSP side | Only one of the two objects, depending on context |
| IFA sent without LMT=0 | GDPR / ATT risk | Check device.lmt before using the IFA |
| schain.complete=0 | Brand-safety DSPs block the inventory | Declare all intermediaries or work directly with the publisher |
Frequently asked questions
What's the difference between OpenRTB 2.5 and 2.6?
OpenRTB 2.6 natively integrates the schain object (which was an extension in 2.5), adds better support for new privacy regulations (GPP), and improves dooh objects for out-of-home programmatic. 2.5 remains the most widely deployed version in production.
How do I know if my bid request is GDPR-compliant?
Three checks: regs.gdpr must equal 1 for European traffic, user.consent must contain a valid TCF 2.x consent string, and the consent string must include the purposes required for the processing you perform. Use the Flownect TCF Decoder to verify consented purposes.
What does at=1 (first price) change for DSPs?
In a first-price auction, the winner pays exactly their bid — not second price + 0.01. DSPs must adapt their bidding strategy: bid the true perceived value rather than bidding high to "win easily." The shift to first price has generally reduced average CPMs as DSPs calibrated their bids downward.
What does the "ext" field mean in a bid request?
The ext field is a proprietary extension zone — each SSP can add its own fields not defined in the standard spec. You'll typically find the Prebid version used, additional targeting metadata, or traffic quality indicators. These fields aren't standardized and vary from one SSP to another.