In early October 2026 the IAB Tech Lab opened public comment on Programmatic Best Practices v1, including guidance to stop rotating placement IDs when one slot accepts native, display, and video. Multiformat impressions are the norm on in-app feed inventory. The native contract still lives in a string inside imp.native.request, and the creative answer still lives in another string in bid.adm. Trade coverage of the comment period landed around October 6, 2026. When you debug fill, you need the asset map on one page, not another lecture about JSON escaping.
This sheet is for engineers who validate bid requests in a dashboard, write bidder adapters, or triage SDK render failures. OpenRTB 2.x transports the Native Ads specification as serialized JSON. Version 1.2 is the production baseline most exchanges cite today. The table below pairs what the publisher asks for in the inner request object with what must come back in the Native Markup Response inside adm.
Request asset to response field map
Each row is one assets[] entry in the inner native request JSON (the payload inside imp.native.request after you parse the string once). The response mirrors the same id values under assets[] in adm.
| Request asset |
required on asset |
Key request fields | Response object | What must come back |
|---|---|---|---|---|
| Title |
1 = must serve |
title.len (max characters) |
assets[].title.text |
Non-empty text within len
|
| Image (icon) |
1 or 0
|
img.type = 1, optional w, h
|
assets[].img with same id
|
url, width and height matching constraints |
| Image (main) |
1 or 0
|
img.type = 3, wmin/hmin or ratio |
assets[].img with same id
|
url; main image aspect per Native 1.2 types list |
| Data (description) | often 1
|
data.type = 2, len
|
assets[].data.value |
Copy within len; type 2 is description |
| Data (sponsored by) | common |
data.type = 1
|
assets[].data.value |
Brand or sponsor line |
| Video (native asset) |
1 when offered |
video.mimes, minduration, maxduration, protocols (all required in request) |
assets[].video.vasttag |
VAST XML string the SDK can hand to a player |
| Link | not an asset row |
link optional in request |
top-level link.url
|
Landing URL; required in response even when request omits it |
| Event trackers (1.2) | per eventtrackers[]
|
event, methods bitmask |
eventtrackers[] with event, method, url
|
Match requested viewability or impression events |
Also keep imp.native.ver aligned with the inner "ver" field (typically "1.2"). A bid response whose outer OpenRTB validates can still ship adm at "1.1" while the request asked for event tracker objects that only exist in 1.2.
Rows that validate and still break in production
Title asset required: 1 with a missing id in adm. OpenRTB only requires that imp.native.request be a string and that adm be a string when mtype declares native. Nothing in the core schema asserts that asset id 2 in the request appears in the response. The exchange accepts the bid; the SDK renders a blank card. Pairing checks belong on the decoded native objects, documented under openrtb-native-asset-required_missing.
Main image type 3 requested, type 1 icon returned. Both sides pass type checks as generic img objects. The mediation SDK expected a 1200×627 main image and received a 80×80 icon. Fill counts as served; viewability and CTR do not recover.
Legacy { "native": { ... } } wrapper inside request. Native 1.1 dropped the root wrapper from 1.0, but older publisher SDKs still emit it. Parsers that expect a flat object accept the string and never descend into assets. See openrtb-native-request-legacy_wrapper and the walkthrough at native-request-is-a-json-string.
How you catch it
An LLM implementing a bidder or an AdCP-to-OpenRTB mapper can emit plausible JSON for both strings and still miss asset ids, required flags, or Native 1.2 event trackers. The RPC and the exchange ACK do not re-run that pairing for you.
RTBlint (cargo install rtblint, npm install rtblint-core, MCP rtblint-mcp) validates the OpenRTB object, decodes imp.native.request, and checks native markup in adm against the request assets. It is independent of IAB Tech Lab and of AAO; the spec does not mandate it, but it is the deterministic check on the wire shape agents keep getting wrong.
When the response row is Video (native asset), assets[].video.vasttag is a full VAST envelope, not a hint. Paste the decoded XML into the VAST tag tester to fetch media and tracking from a live URL, and use the VAST inspector if that tag is a wrapper chain. Native fill often dies on the VAST half after the OpenRTB half already cleared QA.
Start from a known-good fixture in the native bid request example, then diff your production traffic with rtblint validate on the bid response direction.
Where to go next
-
Native ads in OpenRTB:
imp.nativefields, asset type lists, and 1.1 versus 1.2 deltas. - Blog: request is a JSON string: why double encoding on the way in and out breaks naive parsers.
- Rule references above for required asset pairing and legacy wrappers when you need the exact finding id in CI.
Bookmark the table. When multiformat placements share one ID, the native string is still the only place that says which headline and main image the renderer must get back.
Top comments (0)