Guides

ARTF explained: the Agentic RTB Framework and where it sits in the auction

Most agentic advertising happens before the auction: an agent plans a campaign, negotiates a deal, confirms a buy. ARTF is the exception. It defines how agent services run inside the auction path, next to the exchange, with a typed vocabulary for changing a bid request or bid response while the auction is happening. If you operate an exchange or a bidder, this is the agentic specification that touches your hot path.

Where ARTF sits

The Agentic RTB Framework is the execution pillar of AAMP, IAB Tech Lab's umbrella for agentic advertising standards. AAMP covers the planning and trust layers: buyer and seller agent SDKs, agentic audiences, diligence and privacy gates. ARTF covers the part where an agent has milliseconds rather than minutes.

AdCP is the comparison people reach for, and the two sit at different altitudes. AdCP lets agents discover inventory, negotiate and transact, over MCP with JSON payloads and human-scale latency. ARTF is a co-located mutation API over gRPC with an auction-scale time budget. A stack can run both without either one competing for the same job.

ARTF v1.0 went out for public comment in November 2025. It continues under the Agentic Task Force through subsequent AAMP releases rather than being finished and frozen.

The execution model: containers, not callouts

The architectural decision that defines ARTF is that agent services run inside the host's own infrastructure. An exchange or a DSP hosts third-party agent containers co-located with its auction, rather than calling an agent over the public internet.

The reason is latency. A server-to-server enrichment hop costs a round trip you cannot afford inside a tmax budget, and the framework claims large reductions in round-trip time from co-location. The tradeoff is operational: you are running someone else's code beside your auction, which is a security and capacity question before it is a protocol question.

Transport is gRPC with Protocol Buffers. That is a deliberate departure from the JSON over HTTP that the rest of the agentic stack uses, and it is the right call for this altitude.

The data model, which is small

A host sends an RTBRequest carrying:

  • lifecycle, the stage of the auction this call belongs to.
  • id, for correlation.
  • tmax, bounding the mutation round trip including latency. This is the agent's entire budget, and it is separate from the auction's own tmax.
  • the OpenRTB bid_request or bid_response itself.
  • originator: publisher, SSP, exchange, or DSP.
  • applicable_intents, the list of things this agent is permitted to answer with.

The agent returns an RTBResponse containing zero or more Mutation messages plus metadata naming its API version and model version. Zero mutations is a valid answer and should be the common one.

A mutation is four things: an intent, an op (add, remove, or replace), a path, and a typed payload chosen by intent. The payload types import OpenRTB directly. The metrics payload is a list of OpenRTB Metric objects; the content data payload is a list of OpenRTB Data objects. This is not a parallel object model. It is a patch protocol for the bid stream you already run.

One round trip, concretely

The protobuf reads abstractly until you see what a single exchange looks like. A host sends the payload with a budget and a permission list; the agent answers with a patch or with nothing:

host -> agent   RTBRequest
  lifecycle           BID_REQUEST
  id                  "req-8891"
  tmax                12               # ms, includes network
  originator          EXCHANGE
  applicable_intents  [ACTIVATE_SEGMENTS, ADD_METRICS]
  bid_request         { ...OpenRTB 2.6-202505... }

agent -> host   RTBResponse
  api_version         "1.0"
  model_version       "seg-2026-07"
  mutations[0]
    intent            ACTIVATE_SEGMENTS
    op                ADD
    path              "user.data"
    payload           [ { id: "prov-4", name: "Provider", segment: [...] } ]

Three things in that exchange decide whether the integration is safe. The host granted two intents, so a mutation carrying a third is out of scope and should be rejected rather than applied. The budget is 12 milliseconds including network, so an agent that occasionally takes 40 does not slow the auction, it drops out of it. And the payload is a list of OpenRTB Data objects, which means it can be malformed OpenRTB in every way an ordinary bid request can.

The eight intents

applicable_intents is the permission model: a host declares what an agent may attempt, and anything else is out of scope for that call. Mapped onto the OpenRTB fields they land on:

IntentLands on
ACTIVATE_SEGMENTSuser.data[] and content.data[] segments
ACTIVATE_DEALSimp.pmp.deals[]
SUPPRESS_DEALSimp.pmp.deals[], removal
ADJUST_DEAL_FLOORdeals[].bidfloor
ADJUST_DEAL_MARGINcommercial layer, no OpenRTB field
BID_SHADEbid.price on the response
ADD_METRICSimp.metric[]
ADD_CIDScontent.data[].cids and user.data[].cids

Six of the eight touch the request. BID_SHADE touches the response, which means a price can change after the bidder set it. ADJUST_DEAL_MARGIN is the odd one out: no OpenRTB field carries margin, so its effect is not visible in the payload at all, which makes it the hardest to audit after the fact.

What ARTF does not specify

The framework says what an agent may change. It does not say that the result is still a valid bid request for the version the exchange runs, and there is no conformance step in the loop.

ADD_CIDS shows the shape of the problem: a legal intent whose legality as OpenRTB depends on which dated 2.6 snapshot the exchange parses, since cids arrived in 2.6-202505. Two related gaps matter before you integrate. path is a free-form string, so it can address something your version does not have. And composition is undefined, so a host running several agents can receive two individually reasonable mutations that contradict each other.

Each of those is worked through with the failure cases in the post on ARTF mutations, and the missing version handshake in the version negotiation post.

Integrating safely

  • Validate after every stage that can rewrite the payload. Publisher emit, agent mutation, exchange forward. The mutation is the new boundary and it belongs in the same category as the others.
  • Keep the pre-mutation payload. Long enough to answer questions about it. When a bidder reports something impossible, the difference between the two documents is the answer.
  • Pin the snapshot per integration. An agent should validate what its mutation produces against the version its host actually runs, not the newest spec its author read.
  • Scope applicable_intents narrowly. It is the only permission control the framework gives you. Grant the intents an agent needs, not the set it supports.
  • Budget the agent tmax honestly. It bounds the round trip including latency, so an agent that occasionally takes longer does not slow the auction, it drops out of it. Decide what a timeout means before it happens.

The mechanical part of all of this is one call: paste a payload into the tester, run the CLI in the same container as the agent, or give the agent the MCP server as a tool so it checks its own output before it answers.

Further reading