You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
As publisher I want CMP consent passed to downstream providers #312
Trusted Server will act as a consent interpreter — extracting privacy signals from browser cookies/headers, decoding them into structured data, and forwarding standardized consent information to advertising partners via OpenRTB.
This enables publishers to:
Monitor what consent data flows to partners
Audit compliance with privacy regulations
Control consent handling without rebuilding integrations
Key Decisions
1. Interpreter Mode (Not Proxy Mode)
Decision: Decode consent strings and forward structured data, rather than just passing raw strings through.
Why: Raw proxy mode provides no observability. Publishers adopt server-side consent management specifically to gain visibility and control over how their users' privacy choices are handled.
Tradeoff: Requires maintaining consent decoders (TCF, GPP, US Privacy), but this is offset by the value of consent visibility and the ability to enforce publisher policies.
2. Standards-Aligned OpenRTB Forwarding
Decision: Use OpenRTB 2.6 canonical field placement for consent signals.
Fields:
user.consent — IAB TCF consent string
regs.gdpr — GDPR applies flag (0 or 1)
regs.us_privacy — US Privacy String (legacy CCPA format)
Why: These are the standard locations defined by OpenRTB 2.6 and used by Prebid Server and most SSPs. Avoids custom extensions and maximizes partner compatibility.
3. No Geolocation-Based Consent Synthesis
Decision: Only forward consent signals that actually exist (from cookies or headers). Do not synthesize consent strings based solely on user location.
Legal risk for publishers (claiming notice was given when it wasn't)
No actual user interaction to base consent on
Behavior: If no consent signal exists, omit the consent fields from OpenRTB rather than sending placeholder values.
4. GPP String Authority for Section IDs
Decision: Derive gpp_sid (section IDs) from the decoded __gpp string content. Treat __gpp_sid cookie as a transport hint to validate, not the authoritative source.
Why: Prevents mismatch/spoofing where section IDs in one cookie don't match the actual GPP string content.
Publishers control consent behavior via trusted-server.toml:
Basic Settings
[consent]
# "interpreter" = decode + forward structured data (recommended)# "proxy" = forward raw strings onlymode = "interpreter"# Check if consent data has expired based on agecheck_expiration = true# Maximum age in days before consent is considered expiredmax_consent_age_days = 395
GDPR Scope
[consent.gdpr]
# Regions where GDPR applies (ISO 3166-1 alpha-2 codes)# Used for observability/logging, not for synthesizing consentapplies_in = [
"AT", "BE", "BG", "HR", "CY", "CZ", "DK", "EE", "FI", "FR",
"DE", "GR", "HU", "IE", "IT", "LV", "LT", "LU", "MT", "NL",
"PL", "PT", "RO", "SK", "SI", "ES", "SE", # EU members"IS", "LI", "NO", # EEA"GB", # UK GDPR
]
US Privacy States
[consent.us_states]
# States with active comprehensive privacy laws# Config-driven to avoid recompile when new laws passprivacy_states = [
"CA", "VA", "CO", "CT", "UT", "MT", "OR", "TX",
"FL", "DE", "IA", "NE", "NH", "NJ", "TN", "MN",
"MD", "IN", "KY", "RI"
]
GPC (Global Privacy Control) Handling
[consent.us_privacy_defaults]
# How to construct US Privacy string when only Sec-GPC header existsnotice_given = true# Has publisher actually shown CCPA notice?lspa_covered = false# Is publisher subject to LSPA?gpc_implies_optout = true# Should GPC header trigger opt-out?
Note: GPC handling is publisher policy, not a protocol requirement. Publishers configure this based on their actual compliance posture.
Conflict Resolution
When both TCF and GPP strings exist but disagree:
[consent.conflict_resolution]
# How to handle disagreements between GPP and TC String:# "restrictive" = no consent (most privacy-safe, default)# "newest" = use timestamp to decide# "permissive" = yes consent (requires legal review)mode = "restrictive"# How many days newer must one be to automatically win?freshness_threshold_days = 30
Partner Integration
[integrations.prebid.consent]
# How to forward consent to Prebid Server:# "openrtb_only" = use OpenRTB body, strip consent cookies (recommended)# "cookies_only" = forward cookies, don't populate OpenRTB (legacy)# "both" = forward both (not recommended, may conflict)mode = "openrtb_only"# Consent cookies to strip when mode = "openrtb_only"consent_cookie_names = [
"euconsent-v2",
"__gpp",
"__gpp_sid",
"us_privacy",
"usprivacy"
]
Edge Cases
No Consent Cookie in EU
Under TCF, absence of a TC String means consent hasn't been collected yet.
Behavior:
Set regs.gdpr = 1 (GDPR applies)
Omit user.consent (no TC String to forward)
Partners should serve non-personalized ads only
No synthetic consent — the absence IS the signal.
No Consent Signal in US State
When a user is in California but has no us_privacy cookie, no __gpp cookie, and no Sec-GPC header.
Behavior:
Omit regs.us_privacy, regs.gpp, regs.gpp_sid
Let downstream partner handle "no signal" state per their policy
Do NOT synthesize a placeholder string based on geolocation alone
Both TCF and GPP Strings Present
When cookies contain both euconsent-v2 (standalone TCF) and __gpp (which may also contain a TCF section).
Forward both raw strings in OpenRTB for partner transparency
Expired Consent
TC String is present but last_updated timestamp is older than configured max_consent_age_days.
Behavior:
Still forward the raw string (proxy mode compatibility)
Flag as expired in structured data
If check_expiration = true, treat as no consent
If check_expiration = false, forward as normal
GPC Header Without Cookie
Browser sends Sec-GPC: 1 but no us_privacy cookie.
Current issue: Existing code hardcodes Sec-GPC: 1 → us_privacy: "1YYN", making unsupported legal claims (notice given, not LSPA covered).
Fix: Make this publisher-configurable via [consent.us_privacy_defaults] to reflect actual compliance posture.
Open Questions
1. TCF Decoder Scope
Question: How much of the TC String do we need to decode?
The full TCF v2 spec includes:
Core consent (purposes + vendor consents)
Publisher restrictions
Disclosed vendors segment
Allowed vendors segment
For MVP: Do we only need core consent, or full decoding?
2. Dual String Precedence Threshold
Question: Should the freshness threshold be 30 days or different?
Current design uses 30-day window for "GPP wins" vs "TC String wins" decisions. Is this the right balance between cookie sync delays and genuine preference updates?
3. Conflict Resolution Defaults
Question: Should conflict resolution mode default to "restrictive" or allow per-partner configuration?
Most privacy-safe is "restrictive" (deny when unclear), but some publishers may need per-partner flexibility.
4. KV Store Consent Freshness
Question: When cookie AND KV store both have consent data, should we:
Always use cookie (fresher)?
Update KV store on every request?
Only update KV on consent changes?
How to detect "consent changed" efficiently?
Implementation Phases
Phase 1: Extraction + Decoding
Read consent cookies (euconsent-v2, __gpp, us_privacy)
A reference for every consent-related field in an OpenRTB 2.6 bid request as sent by Prebid, with tcfControl and all consent management modules enabled.
When gdpr: 1, every downstream partner must have legal basis (consent or legitimate interest) before processing personal data. Bidders without valid legal basis should be excluded from the auction.
2. TCF v2 Consent String — user.ext.consent
The IAB Transparency & Consent Framework v2 consent string. Base64url-encoded binary that contains:
Core String Segments
Segment
Description
Version
TCF spec version (currently 2)
Created / LastUpdated
Timestamps of consent collection
CMP ID & Version
Which CMP collected consent
Consent Screen
Screen number in the CMP flow
Consent Language
ISO 639-1 language code
Vendor List Version
GVL version the CMP was using
Purpose Consents
Bitfield for Purposes 1-12
Purpose LI Transparency
Bitfield for legitimate interest per purpose
Vendor Consents
Bitfield of consented GVL vendor IDs
Vendor LI
Bitfield of vendor legitimate interest
Publisher Restrictions
Per-vendor purpose restriction overrides
TCF Purposes Relevant to Prebid
Purpose
Name
What It Gates in Prebid (tcfControl)
1
Store/access info on device
Usersyncs, user ID modules, cookie/localStorage access
2
Basic ads
Whether bid adapters can participate in the auction
3
Create ad profile
Ad profile building (not directly enforced by Prebid)
4
Personalized ads
User FPD transmission; EID transmission if eidsRequireP4Consent
7
Measurement
Whether analytics adapters can fire
SF1
Use precise geolocation
May cause geo data to be truncated
Disclosed Vendors Segment
The TC String may end with a .YAAAAAAAAAAA suffix — this is the Disclosed Vendors segment encoding which vendors were shown to the user in the CMP UI.
[!important] tcfControl Enforcement
If Purpose 1 consent is not granted, all EIDs should be blocked from being set. If the relevant transmit purpose is missing, EIDs are stripped from the bid request before it reaches adapters. The eidsRequireP4Consent flag in tcfControl config controls whether P4 specifically is required or any P2-P10 suffices.
With debug: true, Prebid logs enforcement decisions to the console — look for TCF2 enforcement messages showing which adapters/modules are allowed or blocked per purpose.
Activity
ChristianPavilonis commentedon Feb 17, 2026
Consent Forwarding Proposal
Summary
Trusted Server will act as a consent interpreter — extracting privacy signals from browser cookies/headers, decoding them into structured data, and forwarding standardized consent information to advertising partners via OpenRTB.
This enables publishers to:
Key Decisions
1. Interpreter Mode (Not Proxy Mode)
Decision: Decode consent strings and forward structured data, rather than just passing raw strings through.
Why: Raw proxy mode provides no observability. Publishers adopt server-side consent management specifically to gain visibility and control over how their users' privacy choices are handled.
Tradeoff: Requires maintaining consent decoders (TCF, GPP, US Privacy), but this is offset by the value of consent visibility and the ability to enforce publisher policies.
2. Standards-Aligned OpenRTB Forwarding
Decision: Use OpenRTB 2.6 canonical field placement for consent signals.
Fields:
user.consent— IAB TCF consent stringregs.gdpr— GDPR applies flag (0 or 1)regs.us_privacy— US Privacy String (legacy CCPA format)regs.gpp— IAB Global Privacy Platform stringregs.gpp_sid— GPP section IDs (which privacy frameworks apply)Why: These are the standard locations defined by OpenRTB 2.6 and used by Prebid Server and most SSPs. Avoids custom extensions and maximizes partner compatibility.
3. No Geolocation-Based Consent Synthesis
Decision: Only forward consent signals that actually exist (from cookies or headers). Do not synthesize consent strings based solely on user location.
Why:
Behavior: If no consent signal exists, omit the consent fields from OpenRTB rather than sending placeholder values.
4. GPP String Authority for Section IDs
Decision: Derive
gpp_sid(section IDs) from the decoded__gppstring content. Treat__gpp_sidcookie as a transport hint to validate, not the authoritative source.Why: Prevents mismatch/spoofing where section IDs in one cookie don't match the actual GPP string content.
Data Flow
Browser → Trusted Server
The browser sends consent via standard cookies:
graph LR Browser["Browser with CMP"] -->|euconsent-v2| TS["Trusted Server"] Browser -->|__gpp| TS Browser -->|__gpp_sid| TS Browser -->|us_privacy| TS Browser -->|Sec-GPC header| TSTrusted Server Processing
graph TD Cookies["Consent Cookies"] --> Extract["Extract Raw Strings"] Extract --> Decode["Decode Consent Data"] Decode --> Context["ConsentContext<br/>(structured data)"] Context --> ORTB["Map to OpenRTB Fields"] ORTB --> Partners["Forward to Partners"] Decode --> Log["Observability Layer<br/>(tracing, metrics)"] Context --> KV["KV Store<br/>(consent persistence)"]Trusted Server → Partners
OpenRTB bid requests include standardized consent fields:
{ "user": { "id": "synthetic-123", "consent": "CPXxRfAPXxRfAAfKABENB..." }, "regs": { "gdpr": 1, "us_privacy": "1YNN", "gpp": "DBABM~CPXxRfAPXx...", "gpp_sid": [2, 6] } }Configuration
Publishers control consent behavior via
trusted-server.toml:Basic Settings
GDPR Scope
US Privacy States
GPC (Global Privacy Control) Handling
Note: GPC handling is publisher policy, not a protocol requirement. Publishers configure this based on their actual compliance posture.
Conflict Resolution
When both TCF and GPP strings exist but disagree:
Partner Integration
Edge Cases
No Consent Cookie in EU
Under TCF, absence of a TC String means consent hasn't been collected yet.
Behavior:
regs.gdpr = 1(GDPR applies)user.consent(no TC String to forward)No synthetic consent — the absence IS the signal.
No Consent Signal in US State
When a user is in California but has no
us_privacycookie, no__gppcookie, and noSec-GPCheader.Behavior:
regs.us_privacy,regs.gpp,regs.gpp_sidBoth TCF and GPP Strings Present
When cookies contain both
euconsent-v2(standalone TCF) and__gpp(which may also contain a TCF section).Precedence rules:
Expired Consent
TC String is present but
last_updatedtimestamp is older than configuredmax_consent_age_days.Behavior:
check_expiration = true, treat as no consentcheck_expiration = false, forward as normalGPC Header Without Cookie
Browser sends
Sec-GPC: 1but nous_privacycookie.Current issue: Existing code hardcodes
Sec-GPC: 1→us_privacy: "1YYN", making unsupported legal claims (notice given, not LSPA covered).Fix: Make this publisher-configurable via
[consent.us_privacy_defaults]to reflect actual compliance posture.Open Questions
1. TCF Decoder Scope
Question: How much of the TC String do we need to decode?
The full TCF v2 spec includes:
For MVP: Do we only need core consent, or full decoding?
2. Dual String Precedence Threshold
Question: Should the freshness threshold be 30 days or different?
Current design uses 30-day window for "GPP wins" vs "TC String wins" decisions. Is this the right balance between cookie sync delays and genuine preference updates?
3. Conflict Resolution Defaults
Question: Should conflict resolution mode default to "restrictive" or allow per-partner configuration?
Most privacy-safe is "restrictive" (deny when unclear), but some publishers may need per-partner flexibility.
4. KV Store Consent Freshness
Question: When cookie AND KV store both have consent data, should we:
Implementation Phases
Phase 1: Extraction + Decoding
euconsent-v2,__gpp,us_privacy)Sec-GPCheaderConsentContextstructPhase 2: OpenRTB Integration
Sec-GPC→"1YYN"with configPhase 3: Configuration + Observability
[consent]config to TOMLPhase 4: Partner Integrations
openrtb_onlymodePhase 5: KV Store Integration
Standards References
ChristianPavilonis commentedon Feb 18, 2026
to Enable consent info in prebidjs:
OpenRTB Prebid Consent Fields Reference
A reference for every consent-related field in an OpenRTB 2.6 bid request as sent by Prebid, with tcfControl and all consent management modules enabled.
Field Map
graph TD BidRequest["OpenRTB Bid Request"] BidRequest --> Regs["regs"] Regs --> RegsExt["regs.ext"] RegsExt --> GDPR["gdpr: 0 | 1"] BidRequest --> User["user"] User --> UserExt["user.ext"] UserExt --> Consent["consent (TC String v2)"] UserExt --> EIDs["eids[]"] UserExt --> CPS["ConsentedProvidersSettings"] CPS --> AC["consented_providers (AC String)"] BidRequest --> Source["source"] Source --> SChain["ext.schain"]1. GDPR Applicability —
regs.ext.gdpr10When
gdpr: 1, every downstream partner must have legal basis (consent or legitimate interest) before processing personal data. Bidders without valid legal basis should be excluded from the auction.2. TCF v2 Consent String —
user.ext.consentThe IAB Transparency & Consent Framework v2 consent string. Base64url-encoded binary that contains:
Core String Segments
TCF Purposes Relevant to Prebid
eidsRequireP4ConsentDisclosed Vendors Segment
The TC String may end with a
.YAAAAAAAAAAAsuffix — this is the Disclosed Vendors segment encoding which vendors were shown to the user in the CMP UI.Decoding
Decode with:
@iabtechlab/iabtcf-decoder(npm)3. Google Additional Consent —
user.ext.ConsentedProvidersSettingsGoogle's Additional Consent (AC) string covers ad tech providers not in the IAB Global Vendor List but participating in the Google ecosystem.
22628.2316.3119.2677dvProvider IDs map to Google's ATP list. This is required for Google Ad Manager / AdX demand.
4. Extended User IDs —
user.ext.eidsEIDs carry cross-site or cross-device identifiers. The tcfControl module restricts transmission based on TCF consent:
pubcid.orgid5-sync.comadserver.orgcrwdcntrl.netEach EID entry has the structure:
{ "source": "id5-sync.com", "uids": [{ "id": "ID5*CSYv...", "atype": 1, "ext": { "linkType": 2, "pba": "...", "abTestingControlGroup": false } }] }atype: 1— cookie/device-based IDlinkType: 2— probabilistic match (ID5-specific)abTestingControlGroup— ID5 A/B test holdout flag5. Supply Chain —
source.ext.schain{ "ver": "1.0", "complete": 1, "nodes": [{ "asi": "playbuzz.com", "sid": "0016M00002GucDQQAZ", "hp": 1, "domain": "ts.prospecta.com" }] }complete: 1asisidhp: 1Note
The schain is also duplicated per-impression in
imp[].ext.schain. This is redundant but common in Exco/Playbuzz requests.6. Blocked Categories —
bcatContent safety restrictions that complement consent by limiting ad categories:
IAB25-*IAB9-7,IAB9-WS*IAB17-1/16/18/22IAB7-39IAB26-WS17. Per-Impression Fields —
imp[].extEach impression carries consent-adjacent signals:
gpidtidapschaintcfControl Configuration
The Prebid tcfControl module (added in
crates/js/lib/src/integrations/prebid/index.ts) enforces these rules:With
debug: true, Prebid logs enforcement decisions to the console — look forTCF2 enforcementmessages showing which adapters/modules are allowed or blocked per purpose.