Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion extensions/community_extensions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,10 @@ See [extended-content-ids.md](extended-content-ids.md) for deatils.

#### Notes

See [seat-non-bid.md](seat-non-bid.md) for deatils.
See [seat-non-bid.md](seat-non-bid.md) for deatils.

### Agentic Audiences

#### Notes

See [agentic-audiences.md](agentic-audiences.md) for details. Agentic Audiences (formerly UCP) defines how to convey vector embeddings—identity, contextual, and reinforcement signals—in `BidRequest.user.data` using the Data/Segment structure.
182 changes: 182 additions & 0 deletions extensions/community_extensions/agentic-audiences.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
# Agentic Audiences in OpenRTB

**Sponsors**: LiveRamp

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can add raptive

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

## Overview

Agentic Audiences (formerly the User Context Protocol/UCP) is an open standard that defines how intelligent agents in advertising exchange signals—identity, contextual, and reinforcement information—that represent a consumer's real-time intent and response to advertising. Agentic Audiences has been added to IAB Tech Lab's open-source agentic initiative and is maintained in the [IABTechLab/agentic-audiences](https://github.com/IABTechLab/agentic-audiences) repository.

Rather than exchanging raw data points or text descriptions, Agentic Audiences leverages **embeddings**—compact, learned vector representations that efficiently encode complex signals in a privacy-preserving, interoperable format. This enables the sub-100ms response times required for real-time bidding.

## Request Change

This community extension defines how Agentic Audiences embeddings are conveyed in OpenRTB bid requests. The extension uses the existing `Data` and `Segment` objects in `BidRequest.user.data`. Each data provider supplies one or more segment entries, where each entry is a vector embedding with metadata describing its type and model.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Community extensions use ext fields, so all these extra fields should hand off user.data.sement.ext if you're going to use segment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed


## Specification

### Object: `BidRequest.user.data`

Per the OpenRTB 2.x API, the `Data` object array in `user.data` allows additional data about the user to be specified. For Agentic Audiences, each provider contributes one `Data` object with:

- **name**: Provider identifier in snake_case (e.g., `live_ramp`, `optable`). Used to identify the source of the embedding data.
- **segment**: Array of Agentic Audiences segment entries (see below).

### Object: `Data.segment` (Agentic Audiences Segment Extension)

When conveying Agentic Audiences embeddings, each element in the `segment` array is an object with the following attributes:

<table>
<thead>
<tr>
<td><strong>Attribute</strong></td>
<td><strong>Type</strong></td>
<td><strong>Description</strong></td>
</tr>
</thead>
<tbody>
<tr>
<td><code>ver</code></td>
<td>string</td>
<td>Specification version for embedding schema compatibility (e.g., "1.0").</td>
</tr>
<tr>
<td><code>vector</code></td>
<td>number array</td>
<td>Vector embedding as a float array. Typically 256–1024 dimensions.</td>
</tr>
<tr>
<td><code>model</code></td>
<td>string</td>
<td>Model identifier that produced the embedding (e.g., "sbert-mini-ctx-001", "optable-embed-v1").</td>
</tr>
<tr>
<td><code>dimension</code></td>
<td>number</td>
<td>Vector dimension (length of the <code>vector</code> array).</td>
</tr>
<tr>
<td><code>type</code></td>
<td>number array</td>
<td>Embedding type(s): 1 = identity, 2 = contextual, 3 = reinforcement. An entry may encode multiple signal types.</td>
</tr>
</tbody>
</table>

### List: Embedding Type Values

<table>
<thead>
<tr>
<th>Value</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Identity – Who the user is (hashed identifiers, segments, behavioral history)</td>
</tr>
<tr>
<td>2</td>
<td>Contextual – What the user is doing right now (page content, time of day, device, engagement)</td>
</tr>
<tr>
<td>3</td>
<td>Reinforcement – How the user responds to advertising (impressions, clicks, conversions, engagement)</td>
</tr>
</tbody>
</table>

### Known Providers

When integrating with client-side or server-side sources, the following provider names (snake_case) are commonly used:

| Provider | Data object <code>name</code> | Notes |
| -------- | ---------------------------- | ----- |
| LiveRamp | <code>live_ramp</code> | Default storage key: <code>_lr_agentic_audience_</code> |
| Optable | <code>optable</code> | Default storage key: <code>_optable_agentic_audience_</code> |

Additional providers may use their own identifier in snake_case. Implementations should pass the `name` value unchanged so downstream systems can identify the embedding source.

## Example Bid Request

### Single provider (LiveRamp only)

```json
{
"id": "req-12345",
"imp": [{ "id": "1", "banner": { "w": 300, "h": 250 } }],
"user": {
"data": [
{
"name": "live_ramp",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Liveramp is one word

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

"segment": [
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The next five fields should hang off ext not segment directly or this isn't an extension.

Also according to the aa spec this is rather incomplete

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i fixed it so that the aa specific fields are under ext. in regards to the incompleteness.
these were the minimum ones we thought would be needed in openrtb.
do you believe we should add all fields in the aa spec? are you concerned with request size bloat?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am worried about that but the appendix audience spec says a bunch of fields are required and then it lists even more optional fields, so I'm not sure which is right

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed the ext, ty

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The aa spec's required fields could be pruned down a bit. Also the original spec was meant to cover the targeting side as well, for example metric specification isn't as relevant on the supply side.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can:

  1. we move forward with this small set of fields and add more as needed
  2. we make it follow the AA spec exactly, including nested fields and long form names

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adam-zimmerman @patmmccann i think we should move forward with #1 and add fields as needed by the community

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, let's stick with #1.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay but then you should change the aa spec to move more things to optional

{
"ver": "1.0",
"vector": [0.1, -0.2, 0.3],
"model": "sbert-mini-ctx-001",
"dimension": 3,
"type": [1, 2]
}
]
}
]
}
}
```

### Multiple providers (LiveRamp and Optable)

```json
{
"id": "req-12345",
"imp": [{ "id": "1", "banner": { "w": 300, "h": 250 } }],
"user": {
"data": [
{
"name": "live_ramp",
"segment": [
{
"ver": "1.0",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The spec calls for much longer vectors and the arrays of floats would require much more precision than one decimal place. I think this example is misleading. It is likely wise to use a better data structure than this vector spelled out so poorly compacted

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to ext but this is for version. so version of the model that was used to generate the embedding. not the actual vector or array of floats.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I meant the line below, looks like we already came to agreement ty

"vector": [0.1, -0.2, 0.3],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe something like this instead?

const floats = [
  1.2345678, -2.5, 0.0, 3.1415927, 12345.678,
  -0.00012345, 42.42, -999.999, 0.000001, 987654.25
];

function floats32ToBase64(arr) {
  const buffer = new ArrayBuffer(arr.length * 4);
  const view = new DataView(buffer);

  arr.forEach((x, i) => view.setFloat32(i * 4, x, true)); // little-endian

  const bytes = new Uint8Array(buffer);
  let binary = "";
  for (const b of bytes) binary += String.fromCharCode(b);

  return btoa(binary);
}

console.log(floats32ToBase64(floats));
// UQaePwAAIMAAAAAA2w9JQLbmQEZbcgG5FK4pQvD/ecS9N4Y1ZCBxSQ==

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're proposing that instead of an array of floats, that the array is encoded to base64. is that to reduce size of the request or is there an issue with just transporting an array of floats?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to reduce the size, the spec talks about it being 512 or 1024 entries long

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was also thinking the array itself should be base64 encoded

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@patmmccann @adam-zimmerman i went ahead and changed vector to be a base64 encoded value. along with examples on encoding and decoding

"model": "sbert-mini-ctx-001",
"dimension": 3,
"type": [1]
}
]
},
{
"name": "optable",
"segment": [
{
"ver": "1.0",
"vector": [0.5, 0.6, -0.1],
"model": "optable-embed-v1",
"dimension": 3,
"type": [2]
}
]
}
]
}
}
```

*Note: Embedding vectors in examples are truncated for illustration; actual vectors are typically 256–1024 dimensions.*

## Storage (Client-Side)

When Agentic Audiences data is sourced from browser storage (localStorage or cookie), the stored value **must be base64-encoded** JSON. The decoded structure must include an `entries` array, where each entry has: `ver`, `vector`, `model`, `dimension`, and `type`. The wire format sent in the bid request uses the decoded `entries` as the `segment` array for that provider's `Data` object.

## Implementation Notes

- **Vector dimensions**: Embedding vectors are typically 256–1024 dimensions. Implementers should agree on dimension and vector-space alignment when interoperating across providers.
- **Privacy**: Embeddings encode semantic meaning without exposing raw user data. Implementers must ensure appropriate consent and data handling policies are followed.
- **Model interoperability**: The `model` field enables downstream systems to select compatible embeddings. Similarity computations are meaningful only within the same model/vector space.
- **Related implementations**: [Prebid.js Agentic Audience Adapter](https://github.com/prebid/Prebid.js/pull/14626) (RTD module <code>agenticAudienceAdapter</code>) reads from browser storage and injects Agentic Audiences data into the OpenRTB bid request per this specification.

## References

- [Agentic Audiences | IAB Tech Lab](https://iabtechlab.com/standards/agentic-audiences/)
- [Agentic Audiences GitHub Repository](https://github.com/IABTechLab/agentic-audiences)
- [Prebid.js Agentic Audience Adapter (PR #14626)](https://github.com/prebid/Prebid.js/pull/14626)