Skip to content

Write Lockr IDs to KV store #1246

Open

Description

@jevansnyc

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.

Activity

  1. added this to the 202610 milestone on Oct 8, 2026
  2. added theissue type on Oct 8, 2026
  3. ChristianPavilonis commented on Oct 8, 2026

    @ChristianPavilonis
    Collaborator

    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:

    1. 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.
    2. 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.
    3. 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.
    4. 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:

    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.

  4. ChristianPavilonis commented on Oct 8, 2026

    @ChristianPavilonis
    Collaborator

    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 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.
    • Update the PrebidUserIdEid input shape around line 1010 as needed. The shared output type is AuctionEid in lib/src/core/auction.ts:31.
    • 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:

    File What to inspect/change
    crates/trusted-server-core/src/openrtb.rs:70 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.
    crates/trusted-server-core/src/auction/endpoints.rs:485 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.
    crates/trusted-server-core/src/ec/prebid_eids.rs:33 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.
    • lib/test/core/auction.test.ts covers buildAdRequest() EID pass-through.
    • 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions