Blog · Protocol

imp.native.request is a JSON string, not a nested object.

OpenRTB 2.x did not nest the Native request as JSON objects under imp.native. It stuffed a whole Native markup request, itself JSON, into a string field named request. A decoder that maps that field to map[string]any or a struct will fail closed or, worse, fail open and bid without assets.

Two JSON documents, one HTTP body

The bid request is JSON. The Native request is also JSON. The second document is quoted inside the first. That is IAB Native 1.1/1.2 as carried by OpenRTB 2.x, not a vendor quirk. imp.native.request is a string. imp.native.ver names the Native spec version. Assets, eventtrackers, and context live inside the string.

{
  "id": "req-1",
  "imp": [{
    "id": "1",
    "native": {
      "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":140}}]}",
      "ver": "1.2"
    }
  }]
}

If your type for request is an object, most languages will error on unmarshal. If your type is json.RawMessage or string and you never parse it, you will bid on a native impression whose title length, image sizes, and required assets you never read. That looks like fill. It is inventory you cannot render.

Where it breaks in production

Exchanges sometimes send the Native object unquoted because an internal model already had structs. Bidders that only accept a string then drop the imp. Bidders that only accept an object drop the spec-shaped requests. Both payloads exist. A single integration test against one exchange will not show the other dialect.

OpenRTB 3.0 / AdCOM moved Native into the shared object model so this double encoding could die. Plenty of 2.6 traffic has not moved. If you still speak 2.x, you still have a string.

What to check

  • Decode imp.native.request as a string, then JSON-parse that string into the Native request. Do not skip the second parse.
  • Read ver on both the OpenRTB native object and inside the request document. They should agree. When they do not, pick a policy and log it.
  • Reject required assets you cannot fill. A bid with empty adm native markup is how you win and then fail to render.
  • Paste a real native request into the tester. The Native object reference is the field list.

The honest limit

This is a parse contract, not a fraud check. A well-formed string can still describe MFA inventory. RTBlint reports when the native payload is not usable as specified. It does not score content quality. Independent of IAB Tech Lab.

Sources