Intermediate Learning Track

Master OpenRTB 2.6

Read every bid request like an engineer. Decode compliance signals, predict auction outcomes, and spot revenue killers in real time. Built for TAMs, yield ops, and anyone troubleshooting the bidstream.

Intermediate track

Master the bidstream before troubleshooting yield

For intermediate practitioners: you understand programmatic flow, now decode every request field, predict auction outcomes, and spot compliance issues in real time.

What you'll learn

  • Every OpenRTB 2.6 object (imp, site, device, user, regs, source) and why it matters
  • How consent, identity, and compliance signals unlock or block demand
  • Bid response mechanics: nurl vs burl, loss reason codes, and win-notice billing

How this guide works

  • Fully annotated, real-world bid request and response examples with field-by-field breakdown
  • Reference tables for every object: type, required status, and revenue impact if missing
  • Six common failure patterns — how to spot them and fix them in minutes

How to use it

  • Keep an SSP export open in another window — decode alongside the guide
  • Mark suspicious fields (blank geo, missing consent, wrong device type) as you read
  • Build your own "red flags" checklist to apply to any bid log

Why OpenRTB matters

OpenRTB 2.6 is the bidstream protocol. Every field in a bid request is a signal: it tells a DSP whether to bid, how much to bid, and under what legal constraints. A missing geo field? Geo-targeted campaigns skip your impression entirely. Blank consent string in GDPR traffic? Most compliant DSPs no-bid without attempting. Wrong device type on your CTV inventory? CTV-specific budgets go elsewhere.

The cost of a single malformed request can ripple through your entire demand stack. But professionals who can decode these payloads—identifying red flags, spotting compliance gaps, understanding why bids are missing—diagnose yield issues in minutes instead of days. This guide teaches you how.

How an OpenRTB auction works — in 6 steps

  1. Publisher triggers an ad request — the page or app fires a request to the SSP when an ad slot loads.
  2. SSP builds the bid request — assembles the OpenRTB JSON payload with imp, site/app, device, user, regs, source objects.
  3. SSP fans out to DSPs — sends the same payload (or per-DSP variations) to connected buyers within the tmax window (typically 100–300 ms).
  4. DSPs respond with bid responses — each responding DSP returns a seatbid with a price, creative markup (adm), and metadata.
  5. SSP runs the auction — compares all bids against the floor (bidfloor), applies any deal priority, selects the winner.
  6. Win notice and billing — SSP fires the winning DSP's nurl (win notice URL) with the clearing price substituted into the macro ${AUCTION_PRICE}.

Annotated bid request (OpenRTB 2.6)

A realistic example covering banner, site context, geo, identity, and consent. Each key section is explained below the payload.

JSON OpenRTB 2.6 — Bid Request
{
  "id": "7d9b6c3a-1f4e-4b8a-9c2d-0e5f8a1b7c3e",   // Unique auction ID — matches bid response id
  "at": 1,                                              // Auction type: 1 = first-price, 2 = second-price
  "tmax": 150,                                          // Timeout in ms — DSPs must respond within this
  "cur": ["USD"],

  "imp": [
    {
      "id": "1",
      "banner": {
        "w": 300, "h": 250,
        "api": [3, 5]                          // 3=MRAID 2.0, 5=ORMMA — supported APIs
      },
      "bidfloor": 1.50,                                 // Minimum CPM — bids below this are ignored
      "bidfloorcur": "USD",
      "secure": 1,                                      // 1 = HTTPS required for all creative assets
      "tagid": "ad-unit-leaderboard-home"               // Publisher-defined placement label
    }
  ],

  "site": {
    "id": "site-abc-001",
    "page": "https://example.com/article/adtech-101",
    "domain": "example.com",
    "cat": ["IAB12"],                                   // IAB content category — used for brand safety
    "publisher": {
      "id": "pub-456",
      "name": "Example Media"
    },
    "ref": "https://google.com/search?q=adtech"         // Referring URL — signals intent context
  },

  "device": {
    "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    "ip": "203.0.113.42",                              // Truncated or hashed in GDPR regions
    "geo": {
      "country": "USA",
      "region": "CA",
      "city": "Los Angeles",
      "lat": 34.0522, "lon": -118.2437,
      "type": 2                                         // 1=GPS, 2=IP-derived, 3=user-provided
    },
    "devicetype": 2,                                    // 1=PC, 2=Phone, 3=Tablet, 4=TV, 5=Game Console, 6=Watch
    "os": "Windows",
    "language": "en",
    "dnt": 0                                            // Do Not Track — 0=no restriction, 1=limit tracking
  },

  "user": {
    "id": "u-78901-hashed",                            // Publisher or SSP user ID (not exposed in GDPR scope)
    "buyeruid": "buyer-xyz-001",                       // DSP's own user ID synced via cookie sync
    "consent": "CPXxRfAPXxRfAAfKABENAfCIAP_AAH_AAAqIHItf...", // IAB TCF v2 consent string
    "ext": {
      "eids": [                                                  // Extended IDs — clean-room / cookieless identity
        {
          "source": "liveramp.com",
          "uids": [{ "id": "RampID-abcde12345", "atype": 3 }]
        },
        {
          "source": "uidapi.com",
          "uids": [{ "id": "TDID-00112233aabbcc", "atype": 1 }]
        }
      ]
    }
  },

  "regs": {
    "coppa": 0,                                         // 1 = COPPA applies — no behavioral targeting
    "ext": {
      "gdpr": 1,                                        // 1 = GDPR applies — consent string required
      "us_privacy": "1YNN"                             // CCPA string: 1=spec ver, Y=notice, N=opt-out, N=LSPA
    }
  },

  "source": {
    "tid": "7d9b6c3a-1f4e-4b8a-9c2d-0e5f8a1b7c3e",  // Must match bid request id for traceability
    "pchain": "publisher:pub-456,exchange:ex-001"       // Supply chain transparency (see ads.txt / sellers.json)
  }
}
💡 Field completeness = fill rate. Every DSP filters at the request level before running any auction math. Missing geo? Filtered out. No consent string in EU? Dropped to avoid GDPR liability. Wrong device type? Campaign filter fails. One bad field = one lost bid. Professional SSPs complete these fields obsessively.

Key fields explained

  • imp[].bidfloor Minimum CPM (in bidfloorcur currency). Bids below this are silently dropped — the DSP sees no error. Floors set too high cause low fill; too low reduces revenue.
  • imp[].secure Must be 1 for HTTPS pages. If 0 or missing on a secure page, DSPs serving HTTPS-only creatives will no-bid even if they win the price check.
  • device.devicetype Controls which campaigns target this inventory. CTV campaigns require 3 (SmartTV) or 4 (SetTopBox). Wrong value routes mobile-only budgets to desktop — or vice versa.
  • device.geo.type Tells buyers how accurate the location is. GPS-derived (1) commands a premium; IP-derived (2) is standard; missing geo is a no-bid trigger for geo-targeted campaigns.
  • user.consent IAB TCF v2 consent string. Must be present when regs.ext.gdpr=1. An empty or malformed string causes GDPR-compliant DSPs to drop the bid. Use the IAB consent string decoder to verify purposes are set.
  • user.ext.eids Cookieless identity signals (RampID, UID2, etc.). DSPs with identity graphs match these to their own profiles — no eids = no match rate = lower CPM from identity-enabled buyers.
  • regs.ext.us_privacy CCPA string, format 1YNN. Position 2 = notice given, position 3 = opted out of sale. If position 3 is Y, many DSPs suppress retargeting.
  • source.pchain Supply chain identifier. Required by many DSPs to verify ads.txt/sellers.json compliance. Missing or mismatched pchain causes brand-safety blocks.
  • tmax Total timeout in ms from SSP sending to receiving DSP responses. DSPs use this to decide if they can run ML scoring in time. Values below 100 ms cause many adapters to no-bid without attempting.

Annotated bid response

The DSP's reply. The SSP selects the winning bid, fires the nurl win notice, and serves the adm creative markup.

JSON OpenRTB 2.6 — Bid Response
{
  "id": "7d9b6c3a-1f4e-4b8a-9c2d-0e5f8a1b7c3e",   // Must match bid request id exactly
  "cur": "USD",
  "seatbid": [
    {
      "seat": "dsp-seat-001",                       // Buyer seat ID registered with the SSP
      "bid": [
        {
          "id": "bid-00a1b2c3",                    // DSP-generated bid ID
          "impid": "1",                            // Must match imp[].id from the request
          "price": 2.85,                           // CPM in USD — compared against bidfloor (1.50)
          "adid": "creative-55",
          "adm": "<script src='https://cdn.dsp.example/ad.js'></script>", // Creative markup served to the page
          "adomain": ["advertiser.com"],           // Advertiser domain — used for brand safety and ads.txt checks
          "iurl": "https://cdn.dsp.example/preview.png", // Image preview URL for SSP review
          "cid": "campaign-99",
          "crid": "creative-55",                   // Creative ID — used to block specific creatives
          "cat": ["IAB12"],                        // Advertiser category — must not conflict with site.cat blocks
          "w": 300, "h": 250,
          "nurl": "https://pixel.dsp.example/win?p=${AUCTION_PRICE}&id=bid-00a1b2c3",
          // ↑ Win notice URL. SSP fires this on win, substitutes real clearing price into ${AUCTION_PRICE}
          "burl": "https://pixel.dsp.example/bill?p=${AUCTION_PRICE}",
          // ↑ Billing notice (OpenRTB 2.6+) — fires when impression is billable (viewable or rendered)
          "lurl": "https://pixel.dsp.example/loss?reason=${AUCTION_LOSS}"
          // ↑ Loss notice — SSP fires with loss reason code (e.g. 102=below floor, 100=bid timeout)
        }
      ]
    }
  ]
}
⚠️ Critical billing bug: nurl fires on win (before rendering). burl fires only when impression is rendered/billable. In first-price auctions, if DSPs bill on nurl, you're reporting delivery that never renders. Always verify with the DSP: "Which pixel fires for billing reconciliation?" One DSP billing on nurl can create 20–40% phantom delivery. Check your reconciliation reports monthly.

OpenRTB object reference

Key objects, their required/optional status, and what breaks when they are missing.

Object / Field Type Required? What breaks if missing
imp[].bidfloor float Recommended No floor = DSPs may bid penny prices; yield drops
imp[].secure int (0/1) Required on HTTPS HTTPS-only DSPs no-bid; mixed content warnings
site.page string (URL) Strongly recommended Brand-safety scanning fails; many DSPs no-bid
device.ua string Recommended Device targeting breaks; fraud signals weaken
device.geo object Recommended Geo-targeted campaigns skip this impression entirely
device.devicetype int Recommended Device type targeting fails; CTV/mobile budgets miss
user.consent string (TCF) Required (GDPR) GDPR-compliant DSPs no-bid 100% in EU traffic
user.ext.eids array Optional Identity-based targeting fails; lower CPM from ID-enabled DSPs
regs.ext.gdpr int (0/1) Required (GDPR) Missing = ambiguity; most buyers treat unknown as regulated
regs.ext.us_privacy string Required (CCPA) CCPA-compliant DSPs may default to suppressing retargeting
source.pchain string Recommended Brand-safety DSPs block — cannot verify supply path

Common failure patterns

The most frequent reasons a bid request produces no bids — and how to diagnose them.

Missing or blank geo

Geo-targeted campaigns simply skip the impression. You'll see high bid request volume but low DSP bid rate for campaigns with geo restrictions.

▸ Check: is device.geo populated? Is geo.country set? If IP is hashed for privacy, is fallback geo available?

Missing consent string in GDPR traffic

When regs.ext.gdpr=1 but user.consent is absent, GDPR-compliant DSPs have no legal basis for behavioral targeting and must no-bid. A TCF string must encode at least purposes 1 (storage) and 3 (profiling) to enable most demand.

▸ Check: parse the consent string with the IAB TCF decoder. Confirm purposes 1, 3, 4 are granted.

Wrong devicetype for CTV

CTV inventory sent with devicetype=2 (phone) is invisible to CTV-specific campaigns. Samsung Ads and similar CTV DSPs filter on devicetype at the first pass.

▸ Check: CTV apps should send devicetype=3 (SmartTV) or devicetype=4 (SetTopBox). Confirm with the publisher's SDK configuration.

Bid below floor (102)

Floor set too aggressively for the audience or content tier. The SSP returns loss reason code 102 to the DSP. You may see this in the lurl firing with reason=102.

▸ Check: compare bidfloor against DSP bid distribution in your reporting. A floor above the 75th percentile of bids clears most demand.

Timeout (tmax too low)

tmax under 100 ms causes many DSPs to no-bid without even attempting ML scoring. Loss reason 100 (bid expired) or 0 (no response) in lurl indicates this.

▸ Check: raise tmax to at least 150 ms for web, 200 ms for CTV. Coordinate with DSP partners on their minimum bidder latency.

adomain / adcat mismatch

Bid wins the auction but the creative is blocked by the publisher's block list. The SSP fires the nurl but returns an error page or empty slot.

▸ Check: compare bid.adomain against site publisher block lists. A DSP may routinely submit from a different adomain than the apparent advertiser.

No-bid reason codes (NBR)

When a DSP wants to explain a no-bid, it returns a 204 with a nbr field. Not all DSPs populate this, but it is critical for diagnostics when they do.

CodeMeaningCommon cause
0Unknown errorDSP-side issue; contact their support team
1Technical errorMalformed JSON or missing required field
2Invalid requestOpenRTB version mismatch or unsupported extension
3Known web spider / botIVT detected by DSP — check traffic quality
5No inventory matchPublisher, domain, or category blocked by DSP
6No audience matchNo user ID match — cookieless or sync gap
7Below floorDSP bid lower than bidfloor — raise campaign CPM or lower floor
9User opt-out / blockedConsent string missing purposes or user opted out

Apply what you've learned

Three practical drills to build diagnostic skills you can apply to any production bidstream. Each one produces an artifact you can reuse.

🎯 Drill 1 — Annotate 20 real bid requests

  • Export 20 raw bid requests from your SSP sandbox or production logs (sample from last hour).
  • For each request, mark: top 5 revenue signals (geo, consent, device type, floor, page category) and their values.
  • Red-flag any missing/malformed field: blank geo, empty consent string, missing device type, floor below market.
  • Output: bid-request-audit.csv — columns: request_id | field | value | risk_level | action. Share with your team.
  • Time estimate: 30–45 minutes for 20 requests.

🔐 Drill 2 — Consent string decoder practice

  • Pull 10 real user.consent values from your GDPR-region traffic (EU, UK).
  • Decode each using the IAB TCF v2 Consent Decoder (github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework).
  • For each string: which purposes are granted? Does it include purposes 1, 3, 4 (storage, profiling, personalization) that most DSPs require?
  • Output: consent-matrix.csv — consent_string_id | purpose_1 | purpose_3 | purpose_4 | full_decode_link. Identify high-risk strings (missing key purposes).
  • Time estimate: 20 minutes. Reveals patterns in your consent collection.

📊 Drill 3 — No-bid root cause analysis

  • Pull all bid requests that received 0 bids from your SSP for one representative week of traffic.
  • Sample 50–100 requests. Apply the failure patterns from this guide: missing geo, blank consent, wrong device type, floor too high, tmax too low.
  • Categorize each no-bid: which pattern explains it? Estimate % of traffic in each category.
  • Output: nobid-rca.md with: failure category | % of traffic | revenue impact estimate | fix priority. Share with your yield ops team.
  • Time estimate: 1 hour. One session often reveals $XXX/day in low-hanging fruit.

🔗 References & deep dives

  • OpenRTB 2.6 spec — github.com/InteractiveAdvertisingBureau/openrtb (the source of truth for all fields)
  • IAB TCF v2.2 decoder — github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework (decrypt any consent string)
  • ads.txt / sellers.json — spec.iabtechlab.com/ads-txt/ (verify supply chain transparency and fight fraud)
  • Loss reason codes — Appendix B of OpenRTB 2.6 spec (diagnostic codes in bid response 204s)
  • GDPR / COPPA / CCPA compliance — See IAB guidelines for regs.ext.gdpr, regs.coppa, regs.ext.us_privacy field requirements

AdTech Toolkit

Enter any two values
to calculate the third

More tools coming soon