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
Lockr's IDs never reach the TS server-side auction. The SDK pushes the ID5 eid into ortb2.user.ext.eids, not the Prebid User ID module. TS collects eids with getUserIdsAsEids() in index.ts:1810, which returned only criteo.com and pubcid.org, and no ts-eids cookie was set. So client-side bidders see the Lockr ID5 and the SSAT auction does not.
Confirmed with live Chrome/Playwright captures on 2026-10-08, comparing direct https://www.example.com/ with the TS matched arm through ts dev proxy --from www.example.com --to ts.example.com. Both runs retained the www.example.com origin and included an initial load plus reload. A fresh DataDome cookie allowed both captures to complete.
The Lockr ID5 token is successfully supplied and persisted on the TS page. The confirmed loss occurs when TS collects EIDs for its auction/cookie handoff.
Observation
Direct Autoblog
TS matched arm
Lockr page-view API returns an ID5 token
Yes
Yes
id5id cookie is populated and survives reload
Yes
Yes
ID5 appears in pbjs.getConfig('ortb2').user.ext.eids
Yes
Yes
ID5 appears in pbjs.getUserIdsAsEids()
No
No
Outgoing browser requests carry the Lockr ID5
Four captured Rubicon requests carried the exact value
None of six captured /auction payloads included id5-sync.com
The observed population flow:
The SDK calls /publisher/app/v2/identityLockr/settings, then /publisher/app/v2/identityLockr/page-view. Direct traffic goes to identity.loc.kr; TS traffic goes through www.example.com/integrations/lockr/api/..., with successful responses.
The initial page-view request has no existing ID5 token. Its response supplies aimTokens[] with key_name: "id5id" and an advertising_token containing JSON with universal_uid. The response also includes the same UID in ids.id5id.eid.
That exact UID appears in the id5id cookie, initially in localStorage, and in the SDK/Prebid EIDs. The configured EID has source: "id5-sync.com", inserter: "Lockr-For-Publishers", matcher: "", mm: 2, and UID atype: 1.
On reload, the saved cookie remains, and the next page-view request sends the same ID in tokens.ID5 with ID5 in noGenerate. The response returns no new ID5 token, while the existing EID remains available. The bare localStorage id5id key was absent in the final reload snapshot, but the cookie and configured EID persisted.
Correction to the original cookie observation:ts-eids was present in this TS run. It contained other providers' EIDs but omitted ID5. The omission persisted across reload and later auctions, so it is not explained solely by the first auction running before Lockr finishes.
This matches the inspected code at 666953a0:
collectAuctionEids() reads only getUserIdsAsEids(), ignoring configured ortb2.user.ext.eids.
There is also an independently cached ID5 SDK identity with a different UID. The direct Rubicon requests carried the Lockr-supplied UID, not that separate SDK value.
Suggested fix: merge the applicable configured ORTB2 EIDs with User ID module EIDs when collecting for the auction and cookie, deduplicate them, and preserve supported EID provenance metadata through serialization. Validate initial load, reload, and an auction after asynchronous Lockr completion. For the KV part of this issue, also verify the deployed partner registry permits id5-sync.com and confirm ingestion with server-side evidence.
These browser captures establish the API → storage → ORTB2 → missing TS payload/cookie chain. They do not establish whether Lockr internally minted a new identity or looked one up upstream, and they do not verify deployed KV contents. Both captures completed without artifact-capture errors. No application fix was made during this investigation; raw cookies and identifier values are intentionally omitted here.
Implementation breadcrumbs for whoever picks this up. Links below are pinned to the inspected commit, 666953a0de0dbec514b0f0bd5a8b03074f13e62b; relocate by function name if the branch has moved. These are proposed changes and acceptance checks, not an implemented fix.
collectAuctionEids() currently returns early when getUserIdsAsEids is missing and reads only that API. Collect both User ID module EIDs and pbjs.getConfig('ortb2')?.user?.ext?.eids. Read current state when invoked so asynchronously populated IDs are picked up. Validate both inputs independently; a missing/malformed input must not discard the other valid input.
Reuse sanitizeAuctionUid() around line 1074, retain its UID validation, and merge without mutating Prebid's arrays. Deduplicate identical source/UID pairs while retaining distinct UIDs. Specify and test metadata conflict precedence rather than silently overwriting provenance.
Check both callers: buildRequests() around line 2304 and syncPrebidEidsCookie() around line 2888. In particular, the cookie writer has its own early clear-and-return when getUserIdsAsEids is missing. Changing only the collector leaves configured-only EIDs broken there. Make stale-cookie clearing depend on the normalized combined result, with tests for configured-only IDs and for both sources becoming empty.
fitAuctionEidsToCookie() around line 2862 reconstructs each entry as { source, uids }. Preserve any newly supported EID fields here too. Keep the 3072-byte encoded-cookie limit and deterministic truncation; test an oversized merged input so an appended configured EID is not silently assumed to have survived trimming.
2. Carry supported provenance through Rust, not just the browser payload. The observed Lockr EID has top-level inserter, matcher, and mm, in addition to source/uids. Relevant places:
Eid currently has only source and uids, with deny_unknown_fields. Add explicitly typed optional provenance fields if preserving them; update constructors and serialization tests.
parse_client_auction_eids() manually reconstructs { source, uids }; merge_auction_eids() around line 558 also creates new entries. Both need to retain supported fields and apply a tested conflict policy. Preserve current validation, caps, and consent enforcement.
StructuredCookieEid and structured_cookie_eids_to_openrtb() around line 268 currently discard EID-level metadata. Update both for cookie fallback; keep legacy cookie decoding compatible.
The current-request body and cookie-fallback paths are separate: resolve_client_auction_eids() in auction/endpoints.rs:466 prefers a valid body over the cookie. Test both. Adding fields only to JS will not preserve them through these reconstruction steps.
3. Complete the KV path and distinguish it from immediate forwarding.
collect_prebid_eid_updates_from_eids() in ec/prebid_eids.rs:183 skips sources absent from PartnerRegistry. It stores the first valid UID for each registered source. Check the actual deployed [[ec.partners]] configuration for source_domain = "id5-sync.com"; browser forwarding alone does not establish KV ingestion.
EcPartner in settings.rs:385 defines that configuration. KV-derived auction output additionally requires bidstream_enabled = true and the intended openrtb_atype (the observed Lockr UID uses 1). See resolve_partner_ids() / to_eids() in ec/eids.rs. This registry requirement is distinct from forwarding a valid current browser EID.
ec_finalize_response() in ec/finalize.rs:47 ingests incoming request cookies on eligible consented flows. JS writes ts-eids in the wrapped bidsBackHandler (prebid/index.ts:2488), after that auction request has already left. Validate KV on a subsequent eligible request carrying the cookie; do not assume including an EID in the first auction body alone stores it.
KV currently represents a partner UID, not the full EID/provenance object (ec/kv.rs::PartnerIdUpdate, ec/eids.rs::to_eids). Preserving provenance in current-request forwarding does not automatically persist it through KV. Any requirement to retain that metadata in KV needs an explicit schema decision.
4. Extend existing regressions instead of starting a new test harness.
lib/test/integrations/prebid/index.test.ts:2418 covers auction EIDs; the cookie tests start around line 3159. Add configured-only EIDs (including when the User ID API is absent), module-only, both sources, duplicates, malformed input, metadata, empty-state clearing, cookie trimming, and an ORTB2 ID added between two auction calls. Use synthetic IDs/domains in fixtures.
Rust tests live alongside the functions: auction/endpoints.rs has body-vs-cookie precedence, malformed entries, limits, merge precedence, and consent tests; ec/prebid_eids.rs has structured/legacy cookie parsing and unknown-source ingestion tests; ec/finalize.rs has cookie-to-KV synchronization tests. Extend these with the same synthetic EID fixture.
Focused JS command from crates/trusted-server-js/lib: npx vitest run test/integrations/prebid/index.test.ts test/core/auction.test.ts. Use the repository's target-aware Rust test commands and normal CI gates for the implementation.
Live acceptance: load the TS matched arm, wait for Lockr's page-view response, correlate the returned UID with ORTB2, then verify it in a subsequent /auction body and decoded ts-eids. Reload and check persistence. With the same browser cookies and authorized admin access, GET /_ts/admin/eids should list the source in ingest.matched, not unmatched/no_partner. That endpoint is only an ingestion preview; use GET /_ts/admin/ec after an eligible request to verify the stored partner UID and derived auction EIDs. Keep consent-denied regression coverage intact.
The observed Lockr API/proxy flow already supplies and persists the ID. The first implementation target is the generic Prebid EID collector and its serialization/ingestion path; the investigation did not identify a need to change Lockr's token issuance flow.
Activity
ChristianPavilonis commentedon Oct 8, 2026
Confirmed with live Chrome/Playwright captures on 2026-10-08, comparing direct
https://www.example.com/with the TS matched arm throughts dev proxy --from www.example.com --to ts.example.com. Both runs retained thewww.example.comorigin and included an initial load plus reload. A fresh DataDome cookie allowed both captures to complete.The Lockr ID5 token is successfully supplied and persisted on the TS page. The confirmed loss occurs when TS collects EIDs for its auction/cookie handoff.
id5idcookie is populated and survives reloadpbjs.getConfig('ortb2').user.ext.eidspbjs.getUserIdsAsEids()/auctionpayloads includedid5-sync.comThe observed population flow:
/publisher/app/v2/identityLockr/settings, then/publisher/app/v2/identityLockr/page-view. Direct traffic goes toidentity.loc.kr; TS traffic goes throughwww.example.com/integrations/lockr/api/..., with successful responses.aimTokens[]withkey_name: "id5id"and anadvertising_tokencontaining JSON withuniversal_uid. The response also includes the same UID inids.id5id.eid.id5idcookie, initially in localStorage, and in the SDK/Prebid EIDs. The configured EID hassource: "id5-sync.com",inserter: "Lockr-For-Publishers",matcher: "",mm: 2, and UIDatype: 1.tokens.ID5withID5innoGenerate. The response returns no new ID5 token, while the existing EID remains available. The bare localStorageid5idkey was absent in the final reload snapshot, but the cookie and configured EID persisted.Correction to the original cookie observation:
ts-eidswas present in this TS run. It contained other providers' EIDs but omitted ID5. The omission persisted across reload and later auctions, so it is not explained solely by the first auction running before Lockr finishes.This matches the inspected code at
666953a0:collectAuctionEids()reads onlygetUserIdsAsEids(), ignoring configuredortb2.user.ext.eids.syncPrebidEidsCookie()both use that collector.There is also an independently cached ID5 SDK identity with a different UID. The direct Rubicon requests carried the Lockr-supplied UID, not that separate SDK value.
Suggested fix: merge the applicable configured ORTB2 EIDs with User ID module EIDs when collecting for the auction and cookie, deduplicate them, and preserve supported EID provenance metadata through serialization. Validate initial load, reload, and an auction after asynchronous Lockr completion. For the KV part of this issue, also verify the deployed partner registry permits
id5-sync.comand confirm ingestion with server-side evidence.These browser captures establish the API → storage → ORTB2 → missing TS payload/cookie chain. They do not establish whether Lockr internally minted a new identity or looked one up upstream, and they do not verify deployed KV contents. Both captures completed without artifact-capture errors. No application fix was made during this investigation; raw cookies and identifier values are intentionally omitted here.
ChristianPavilonis commentedon Oct 8, 2026
Implementation breadcrumbs for whoever picks this up. Links below are pinned to the inspected commit,
666953a0de0dbec514b0f0bd5a8b03074f13e62b; relocate by function name if the branch has moved. These are proposed changes and acceptance checks, not an implemented fix.1. Fix collection and its callers together. Start in
crates/trusted-server-js/lib/src/integrations/prebid/index.ts.collectAuctionEids()currently returns early whengetUserIdsAsEidsis missing and reads only that API. Collect both User ID module EIDs andpbjs.getConfig('ortb2')?.user?.ext?.eids. Read current state when invoked so asynchronously populated IDs are picked up. Validate both inputs independently; a missing/malformed input must not discard the other valid input.sanitizeAuctionUid()around line 1074, retain its UID validation, and merge without mutating Prebid's arrays. Deduplicate identical source/UID pairs while retaining distinct UIDs. Specify and test metadata conflict precedence rather than silently overwriting provenance.PrebidUserIdEidinput shape around line 1010 as needed. The shared output type isAuctionEidinlib/src/core/auction.ts:31.buildRequests()around line 2304 andsyncPrebidEidsCookie()around line 2888. In particular, the cookie writer has its own early clear-and-return whengetUserIdsAsEidsis missing. Changing only the collector leaves configured-only EIDs broken there. Make stale-cookie clearing depend on the normalized combined result, with tests for configured-only IDs and for both sources becoming empty.fitAuctionEidsToCookie()around line 2862 reconstructs each entry as{ source, uids }. Preserve any newly supported EID fields here too. Keep the 3072-byte encoded-cookie limit and deterministic truncation; test an oversized merged input so an appended configured EID is not silently assumed to have survived trimming.2. Carry supported provenance through Rust, not just the browser payload. The observed Lockr EID has top-level
inserter,matcher, andmm, in addition tosource/uids. Relevant places:crates/trusted-server-core/src/openrtb.rs:70Eidcurrently has onlysourceanduids, withdeny_unknown_fields. Add explicitly typed optional provenance fields if preserving them; update constructors and serialization tests.crates/trusted-server-core/src/auction/endpoints.rs:485parse_client_auction_eids()manually reconstructs{ source, uids };merge_auction_eids()around line 558 also creates new entries. Both need to retain supported fields and apply a tested conflict policy. Preserve current validation, caps, and consent enforcement.crates/trusted-server-core/src/ec/prebid_eids.rs:33StructuredCookieEidandstructured_cookie_eids_to_openrtb()around line 268 currently discard EID-level metadata. Update both for cookie fallback; keep legacy cookie decoding compatible.The current-request body and cookie-fallback paths are separate:
resolve_client_auction_eids()inauction/endpoints.rs:466prefers a valid body over the cookie. Test both. Adding fields only to JS will not preserve them through these reconstruction steps.3. Complete the KV path and distinguish it from immediate forwarding.
collect_prebid_eid_updates_from_eids()inec/prebid_eids.rs:183skips sources absent fromPartnerRegistry. It stores the first valid UID for each registered source. Check the actual deployed[[ec.partners]]configuration forsource_domain = "id5-sync.com"; browser forwarding alone does not establish KV ingestion.EcPartnerinsettings.rs:385defines that configuration. KV-derived auction output additionally requiresbidstream_enabled = trueand the intendedopenrtb_atype(the observed Lockr UID uses1). Seeresolve_partner_ids()/to_eids()inec/eids.rs. This registry requirement is distinct from forwarding a valid current browser EID.ec_finalize_response()inec/finalize.rs:47ingests incoming request cookies on eligible consented flows. JS writests-eidsin the wrappedbidsBackHandler(prebid/index.ts:2488), after that auction request has already left. Validate KV on a subsequent eligible request carrying the cookie; do not assume including an EID in the first auction body alone stores it.ec/kv.rs::PartnerIdUpdate,ec/eids.rs::to_eids). Preserving provenance in current-request forwarding does not automatically persist it through KV. Any requirement to retain that metadata in KV needs an explicit schema decision.4. Extend existing regressions instead of starting a new test harness.
lib/test/integrations/prebid/index.test.ts:2418covers auction EIDs; the cookie tests start around line 3159. Add configured-only EIDs (including when the User ID API is absent), module-only, both sources, duplicates, malformed input, metadata, empty-state clearing, cookie trimming, and an ORTB2 ID added between two auction calls. Use synthetic IDs/domains in fixtures.lib/test/core/auction.test.tscoversbuildAdRequest()EID pass-through.auction/endpoints.rshas body-vs-cookie precedence, malformed entries, limits, merge precedence, and consent tests;ec/prebid_eids.rshas structured/legacy cookie parsing and unknown-source ingestion tests;ec/finalize.rshas cookie-to-KV synchronization tests. Extend these with the same synthetic EID fixture.crates/trusted-server-js/lib:npx vitest run test/integrations/prebid/index.test.ts test/core/auction.test.ts. Use the repository's target-aware Rust test commands and normal CI gates for the implementation.Live acceptance: load the TS matched arm, wait for Lockr's page-view response, correlate the returned UID with ORTB2, then verify it in a subsequent
/auctionbody and decodedts-eids. Reload and check persistence. With the same browser cookies and authorized admin access,GET /_ts/admin/eidsshould list the source iningest.matched, notunmatched/no_partner. That endpoint is only an ingestion preview; useGET /_ts/admin/ecafter an eligible request to verify the stored partner UID and derived auction EIDs. Keep consent-denied regression coverage intact.The observed Lockr API/proxy flow already supplies and persists the ID. The first implementation target is the generic Prebid EID collector and its serialization/ingestion path; the investigation did not identify a need to change Lockr's token issuance flow.
Add proxy-side identity capture design spec for lockr-issued IDs