Summary
Architecture spec for embedding TMP in Prebid Server. TMP runs as a built-in library — no standalone router service. This RFC captures the preliminary design for how providers, identity resolution, and TMPX exposure tokens integrate with the Prebid/GAM stack.
Context
PR #2079 introduces TMPX exposure tokens and country-partitioned identity routing. The Go implementation in adcp-go adds these to the router, client, and protocol types. This RFC addresses the next layer: how the router embeds in Prebid Server and how TMPX tokens flow through GAM.
Key Design Decisions
TMP is a Prebid Server capability, not a Prebid.js module
The TMP router embeds in Prebid Server as a Go library (github.com/adcontextprotocol/adcp-go/router). Zero external dependencies. Prebid Server handles fan-out, merge, and KV generation. Prebid.js passes targeting KVs to GPT — no TMP-specific client code needed.
Browser
│
├── Prebid.js (no TMP-specific module)
│ ├── UID2 / EUID module (existing)
│ ├── LiveRamp ATS module (existing)
│ └── passes server KVs to GPT (existing behavior)
│
▼
Prebid Server (Go)
│
├── TMP library (embedded)
│ ├── context match fan-out → buyer context agents
│ └── identity match fan-out → buyer identity agents
│
├── LiveRamp Envelope sidecar (identity resolution)
│
└── Other modules (OpenRTB adapters, etc.)
│
▼
GAM (via GPT)
├── Line item selection on adcp_pkg KVs
└── %%tmpx_*%% macro substitution at serve time
Provider config carries macro_name
Each provider entry needs a macro_name field that controls the GAM targeting key for that provider's TMPX token:
tmp:
providers:
- id: scope3
endpoint: https://us.tmp.scope3.example/v1
context_match: true
identity_match: true
countries: [US]
uid_types: [uid2, rampid, id5]
macro_name: tmpx_scope3
timeout: 30ms
- id: scope3-eu
endpoint: https://eu.tmp.scope3.example/v1
context_match: true
identity_match: true
countries: [DE, FR, IT, ES, NL, GB]
uid_types: [euid, id5]
macro_name: tmpx_scope3
timeout: 30ms
- id: acme
endpoint: https://tmp.acmeoutdoor.example/v1
context_match: true
identity_match: true
countries: [US]
uid_types: [uid2]
macro_name: tmpx_acme
timeout: 30ms
Regional clusters share a macro_name. scope3 and scope3-eu are the same buyer — GAM doesn't care which cluster generated the token. The router selects the right cluster by country; the TMPX flows through the same GAM macro.
The naming chain is two configs:
Prebid Server provider macro_name: "tmpx_scope3"
│
▼
GAM creative tracking URL: %%tmpx_scope3%%
The sales agent surfaces the macro name during create_media_buy so the buyer knows what to put in their creative tracking URLs.
Identity resolution sequencing
TMP identity match needs a resolved user token. Several identity sources feed into user.ext.eids:
| Identity type |
Source |
How it reaches Prebid Server |
| UID2 |
UID2 module in Prebid.js |
user.ext.eids on the bid request |
| EUID |
EUID module in Prebid.js |
user.ext.eids |
| RampID |
LiveRamp ATS.js → Envelope sidecar |
Sidecar resolves cookie → RampID, injected into user.ext.eids |
| ID5 |
ID5 module in Prebid.js |
user.ext.eids |
The LiveRamp Envelope sidecar runs alongside Prebid Server and resolves the LiveRamp envelope cookie into a RampID. This must complete before TMP fan-out starts, since the resolved RampID may be the best identity to send.
Prebid Server picks the UID from user.ext.eids that the most TMP providers support for the user's country.
TMPX flow through GAM
Buyer identity agent
generates TMPX token "k1.dGVzdC10b2tlbg..."
│
▼
Prebid Server (embedded router)
collects into tmpx_providers {"scope3": "k1.dGVzdC10b2tlbg..."}
maps to macro_name tmpx_scope3 = k1.dGVzdC10b2tlbg...
sets as page-level targeting KV
│
▼
Prebid.js → GPT → GAM
passes KVs through (no TMP logic)
│
▼
GAM at serve time
substitutes %%tmpx_scope3%% → k1.dGVzdC10b2tlbg...
│
▼
Buyer impression pixel
receives token, decrypts with cluster master key
logs per-user exposure, updates frequency state
Targeting KV structure
Prebid Server sets two types of KVs:
| Scope |
Keys |
Purpose |
| Ad unit |
adcp_pkg, adcp_seg, adcp_* (offer macros) |
GAM line item selection |
| Page |
tmpx_{macro_name} |
GAM macro substitution at serve time |
Page-level for TMPX because it's per-provider, not per-ad-unit. All slots on the page share the same tokens.
Onboarding a new buyer
Config only, no code changes:
- Publisher ops adds provider to Prebid Server config (id, endpoint, countries, uid_types, macro_name)
- Sales agent creates media buy, tells buyer their macro is
%%tmpx_{macro_name}%%
- Buyer sets up creative tracking URL with that macro
Request flow
1. Prebid.js sends auction request
user.ext.eids populated by UID modules (existing)
2. Prebid Server enrichment:
a. LiveRamp sidecar resolves envelope → RampID (if needed)
b. TMP runs parallel with OpenRTB bid requests:
- Picks best UID for this country from user.ext.eids
- Context match: page context + packages → buyer context agents
- Identity match: user token + country → buyer identity agents
- Router filters by country + uid_type, strips country
- Merges: eligibility (AND semantics), TMPX tokens per provider
3. Sets targeting KVs on auction response
4. Prebid.js passes KVs to GPT → GAM
5. GAM selects line items, substitutes %%tmpx_*%% at serve time
6. Impression pixel fires with TMPX
Timing
0ms ── Prebid.js sends auction request
├── LiveRamp sidecar resolves envelope (~10ms, if needed)
5ms ── TMP fan-out: context + identity in parallel
├── (parallel with OpenRTB bid requests)
25ms ── TMP results ready, KVs set on response
30ms ── Prebid.js passes KVs to GPT → GAM
100ms ── Creative rendered with %%tmpx_*%% substituted
~200ms── Impression pixel fires
Error handling
| Failure |
Behavior |
| TMP fan-out unreachable |
No TMP KVs, GAM uses non-TMP line items |
| One provider times out |
Other providers' packages activate, missing TMPX dropped |
| LiveRamp sidecar down |
No RampID, TMP uses other UIDs from eids |
| No UID available |
Context match only, no identity match, no TMPX |
| GAM macro empty |
%%tmpx_scope3%% renders empty, buyer pixel handles gracefully |
Open Questions
- Should
macro_name be part of the AdCP protocol spec (on the ProviderEntry in product.json), or purely a publisher-side config in Prebid Server?
- UID priority: Should the protocol define a canonical ordering, or is "most provider coverage" the right heuristic?
- Consent passthrough: How do TCF/GPP consent strings flow from Prebid's consent management to TMP's
ConsentSignals?
Related
Summary
Architecture spec for embedding TMP in Prebid Server. TMP runs as a built-in library — no standalone router service. This RFC captures the preliminary design for how providers, identity resolution, and TMPX exposure tokens integrate with the Prebid/GAM stack.
Context
PR #2079 introduces TMPX exposure tokens and country-partitioned identity routing. The Go implementation in adcp-go adds these to the router, client, and protocol types. This RFC addresses the next layer: how the router embeds in Prebid Server and how TMPX tokens flow through GAM.
Key Design Decisions
TMP is a Prebid Server capability, not a Prebid.js module
The TMP router embeds in Prebid Server as a Go library (
github.com/adcontextprotocol/adcp-go/router). Zero external dependencies. Prebid Server handles fan-out, merge, and KV generation. Prebid.js passes targeting KVs to GPT — no TMP-specific client code needed.Provider config carries
macro_nameEach provider entry needs a
macro_namefield that controls the GAM targeting key for that provider's TMPX token:Regional clusters share a
macro_name.scope3andscope3-euare the same buyer — GAM doesn't care which cluster generated the token. The router selects the right cluster by country; the TMPX flows through the same GAM macro.The naming chain is two configs:
The sales agent surfaces the macro name during
create_media_buyso the buyer knows what to put in their creative tracking URLs.Identity resolution sequencing
TMP identity match needs a resolved user token. Several identity sources feed into
user.ext.eids:user.ext.eidson the bid requestuser.ext.eidsuser.ext.eidsuser.ext.eidsThe LiveRamp Envelope sidecar runs alongside Prebid Server and resolves the LiveRamp envelope cookie into a RampID. This must complete before TMP fan-out starts, since the resolved RampID may be the best identity to send.
Prebid Server picks the UID from
user.ext.eidsthat the most TMP providers support for the user's country.TMPX flow through GAM
Targeting KV structure
Prebid Server sets two types of KVs:
adcp_pkg,adcp_seg,adcp_*(offer macros)tmpx_{macro_name}Page-level for TMPX because it's per-provider, not per-ad-unit. All slots on the page share the same tokens.
Onboarding a new buyer
Config only, no code changes:
%%tmpx_{macro_name}%%Request flow
Timing
Error handling
%%tmpx_scope3%%renders empty, buyer pixel handles gracefullyOpen Questions
macro_namebe part of the AdCP protocol spec (on the ProviderEntry in product.json), or purely a publisher-side config in Prebid Server?ConsentSignals?Related