From 96a9097aafab359cd530e83216a05b5d86011355 Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 21 Jan 2026 12:57:54 -0600 Subject: [PATCH 1/5] UserId Submodule: add LocID (locId) Co-Authored-By: Claude Opus 4.5 --- dev-docs/modules/userid-submodules/locid.md | 194 ++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 dev-docs/modules/userid-submodules/locid.md diff --git a/dev-docs/modules/userid-submodules/locid.md b/dev-docs/modules/userid-submodules/locid.md new file mode 100644 index 0000000000..32771fd425 --- /dev/null +++ b/dev-docs/modules/userid-submodules/locid.md @@ -0,0 +1,194 @@ +--- +layout: userid +title: LocID +description: LocID User ID sub-module +useridmodule: locIdSystem +bidRequestUserId: locId +eidsource: locid.com +example: '"SYybozbTuRaZkgGqCD7L7EE0FncoNUcx-om4xTfhJt36TFIAES2tF1qPH"' +gvlid: 3384 +--- + +## Overview + +LocID is a geospatial identifier provided by Digital Envoy. The LocID User ID submodule retrieves a LocID from a publisher-controlled first-party endpoint, respects applicable privacy framework restrictions, and exposes the identifier to bidders via the standard EIDs interface. + +The endpoint is a first-party or on-premises service operated by the publisher, GrowthCode, or Digital Envoy. The module does not transmit IP addresses from the browser; instead, the server-side endpoint derives location information. + +## Registration + +No registration is required to use this module. Publishers must configure a first-party endpoint that proxies requests to the LocID encryption service. + +## Installation + +Build Prebid.js with the LocID module: + +```bash +gulp build --modules=locIdSystem,userId +``` + +## Configuration + +### Default Mode + +By default, the module proceeds when no privacy framework signals are present (LI-based operation): + +```javascript +pbjs.setConfig({ + userSync: { + userIds: [{ + name: 'locId', + params: { + endpoint: 'https://id.example.com/locid' + }, + storage: { + type: 'html5', + name: '_locid', + expires: 7 + } + }] + } +}); +``` + +### Strict Mode + +To require privacy framework signals before proceeding, set `privacyMode: 'requireSignals'`: + +```javascript +pbjs.setConfig({ + userSync: { + userIds: [{ + name: 'locId', + params: { + endpoint: 'https://id.example.com/locid', + privacyMode: 'requireSignals' + }, + storage: { + type: 'html5', + name: '_locid', + expires: 7 + } + }] + } +}); +``` + +### Configuration with API Key and Alternative ID + +```javascript +pbjs.setConfig({ + userSync: { + userIds: [{ + name: 'locId', + params: { + endpoint: 'https://id.example.com/locid', + apiKey: 'your-api-key', + altId: 'publisher-user-id', + timeoutMs: 1000, + withCredentials: true + }, + storage: { + type: 'html5', + name: '_locid', + expires: 7 + } + }] + } +}); +``` + +## Parameters + +{: .table .table-bordered .table-striped } +| Param | Scope | Type | Description | Example | +| --- | --- | --- | --- | --- | +| name | Required | String | Module identifier. Must be `"locId"`. | `"locId"` | +| params | Required | Object | Configuration parameters. | | +| params.endpoint | Required | String | First-party LocID endpoint URL. See Endpoint Requirements below. | `"https://id.example.com/locid"` | +| params.altId | Optional | String | Alternative identifier appended as `?alt_id=` query parameter. | `"user123"` | +| params.timeoutMs | Optional | Number | Request timeout in milliseconds. | `800` (default) | +| params.withCredentials | Optional | Boolean | Include credentials (cookies) on the request. | `false` (default) | +| params.apiKey | Optional | String | API key passed via the `x-api-key` request header. | `"your-api-key"` | +| params.privacyMode | Optional | String | Privacy mode: `"allowWithoutSignals"` (default) or `"requireSignals"`. | `"allowWithoutSignals"` | +| params.requirePrivacySignals | Optional | Boolean | If `true`, requires privacy signals to be present. Equivalent to `privacyMode: 'requireSignals'`. | `false` (default) | +| storage | Required | Object | Storage configuration for caching the ID. | | +| storage.type | Required | String | Storage type. Use `"html5"` for localStorage. | `"html5"` | +| storage.name | Required | String | Storage key name. | `"_locid"` | +| storage.expires | Optional | Number | TTL in days. | `7` | + +## Endpoint Requirements + +The `endpoint` parameter must point to a first-party proxy or on-premises service, not the LocID Encrypt API directly. + +The LocID Encrypt API requires the client IP address as a parameter. Since browsers cannot determine their own public IP, a server-side proxy is required to: + +1. Receive the request from the browser +2. Extract the client IP from the incoming connection +3. Forward the request to the LocID Encrypt API with the IP injected +4. Return the response (`tx_cloc`, `stable_cloc`) to the browser + +If `altId` is configured, the module appends it as `?alt_id=` to the endpoint URL. + +## Privacy Handling + +LocID operates under Legitimate Interest (GVLID 3384). The module's privacy behavior depends on the configured privacy mode. + +### Default Behavior (allowWithoutSignals) + +- **No privacy signals present**: Module proceeds and fetches the ID +- **Privacy signals present**: Enforcement rules apply + +### Strict Mode (requireSignals) + +- **No privacy signals present**: Module returns `undefined` +- **Privacy signals present**: Enforcement rules apply + +### Privacy Signal Enforcement + +When privacy signals are present, the module does not fetch or return an ID if any of the following apply: + +- GDPR applies and vendor permission (GVLID 3384) is denied +- US Privacy (CCPA) string indicates a processing restriction (third character is `Y`) +- GPP signals indicate an applicable processing restriction + +The module checks for vendor consent or legitimate interest for GVLID 3384 when GDPR applies and vendor data is available. + +## Storage + +The module caches the LocID using Prebid's standard storage framework. Configure storage settings via the `storage` object. + +The endpoint response contains two ID types: +- `tx_cloc`: Transactional LocID (primary) +- `stable_cloc`: Stable LocID (fallback) + +The module uses `tx_cloc` when available, falling back to `stable_cloc` if needed. + +## EID Output + +When available, the LocID is included in the bid request as: + +```json +{ + "source": "locid.com", + "uids": [{ + "id": "SYybozbTuRaZkgGqCD7L7EE0FncoNUcx-om4xTfhJt36TFIAES2tF1qPH", + "atype": 3384 + }] +} +``` + +The `atype` value of `3384` is required for demand partner recognition of LocID. This vendor-specific atype value follows the OpenRTB 2.6 Extended Identifiers specification. + +## Debugging + +```javascript +// Check if LocID is available +pbjs.getUserIds().locId + +// Force refresh +pbjs.refreshUserIds() + +// Check stored value +localStorage.getItem('_locid') +``` From f4a925e9d7cb51d9f3e0d62a8a4af3fe85247dda Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 29 Jan 2026 15:49:02 -0600 Subject: [PATCH 2/5] Update LocID docs: atype 1, remove stable_cloc fallback, add connection_ip - Changed EID atype from 3384 to 1 (device-based identifier per OpenRTB 2.6) - Removed stable_cloc fallback language; module only uses tx_cloc for EID - Updated endpoint spec to return connection_ip for IP-aware cache invalidation - Clarified that stable_cloc is available for proxy operators, not transmitted client-side --- dev-docs/modules/userid-submodules/locid.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dev-docs/modules/userid-submodules/locid.md b/dev-docs/modules/userid-submodules/locid.md index 32771fd425..2067b98c48 100644 --- a/dev-docs/modules/userid-submodules/locid.md +++ b/dev-docs/modules/userid-submodules/locid.md @@ -126,7 +126,7 @@ The LocID Encrypt API requires the client IP address as a parameter. Since brows 1. Receive the request from the browser 2. Extract the client IP from the incoming connection 3. Forward the request to the LocID Encrypt API with the IP injected -4. Return the response (`tx_cloc`, `stable_cloc`) to the browser +4. Return the response (`tx_cloc`, `connection_ip`) to the browser If `altId` is configured, the module appends it as `?alt_id=` to the endpoint URL. @@ -158,11 +158,11 @@ The module checks for vendor consent or legitimate interest for GVLID 3384 when The module caches the LocID using Prebid's standard storage framework. Configure storage settings via the `storage` object. -The endpoint response contains two ID types: -- `tx_cloc`: Transactional LocID (primary) -- `stable_cloc`: Stable LocID (fallback) +The endpoint response contains: +- `tx_cloc`: Transactional LocID (used as the EID value) +- `connection_ip`: The resolved client IP address (used for IP-aware cache invalidation) -The module uses `tx_cloc` when available, falling back to `stable_cloc` if needed. +The module only uses `tx_cloc` for the EID. Any `stable_cloc` in the response is ignored client-side; it is available for proxy/endpoint operators to use in their own caching strategies. ## EID Output @@ -173,12 +173,12 @@ When available, the LocID is included in the bid request as: "source": "locid.com", "uids": [{ "id": "SYybozbTuRaZkgGqCD7L7EE0FncoNUcx-om4xTfhJt36TFIAES2tF1qPH", - "atype": 3384 + "atype": 1 }] } ``` -The `atype` value of `3384` is required for demand partner recognition of LocID. This vendor-specific atype value follows the OpenRTB 2.6 Extended Identifiers specification. +The `atype` value of `1` indicates a device-based identifier per the OpenRTB 2.6 Extended Identifiers specification. ## Debugging From 7d1b629e448aa87c8aebc516507c70acc0f85fe2 Mon Sep 17 00:00:00 2001 From: Brian Date: Mon, 2 Feb 2026 22:18:17 -0600 Subject: [PATCH 3/5] Fix MD032 and MD058 markdownlint errors --- dev-docs/modules/userid-submodules/locid.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dev-docs/modules/userid-submodules/locid.md b/dev-docs/modules/userid-submodules/locid.md index 2067b98c48..b419aaadfc 100644 --- a/dev-docs/modules/userid-submodules/locid.md +++ b/dev-docs/modules/userid-submodules/locid.md @@ -101,6 +101,7 @@ pbjs.setConfig({ ## Parameters {: .table .table-bordered .table-striped } + | Param | Scope | Type | Description | Example | | --- | --- | --- | --- | --- | | name | Required | String | Module identifier. Must be `"locId"`. | `"locId"` | @@ -159,6 +160,7 @@ The module checks for vendor consent or legitimate interest for GVLID 3384 when The module caches the LocID using Prebid's standard storage framework. Configure storage settings via the `storage` object. The endpoint response contains: + - `tx_cloc`: Transactional LocID (used as the EID value) - `connection_ip`: The resolved client IP address (used for IP-aware cache invalidation) From a0570a5f95fa2c2f46b883df0fabd95289ec618f Mon Sep 17 00:00:00 2001 From: Brian Date: Fri, 6 Feb 2026 10:46:09 -0600 Subject: [PATCH 4/5] LocID docs: add ipEndpoint param and IP change detection section --- dev-docs/modules/userid-submodules/locid.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/dev-docs/modules/userid-submodules/locid.md b/dev-docs/modules/userid-submodules/locid.md index 2067b98c48..0a4840d83b 100644 --- a/dev-docs/modules/userid-submodules/locid.md +++ b/dev-docs/modules/userid-submodules/locid.md @@ -39,7 +39,8 @@ pbjs.setConfig({ userIds: [{ name: 'locId', params: { - endpoint: 'https://id.example.com/locid' + endpoint: 'https://id.example.com/locid', + ipEndpoint: 'https://id.example.com/ip' // optional: lightweight IP-only check }, storage: { type: 'html5', @@ -106,6 +107,8 @@ pbjs.setConfig({ | name | Required | String | Module identifier. Must be `"locId"`. | `"locId"` | | params | Required | Object | Configuration parameters. | | | params.endpoint | Required | String | First-party LocID endpoint URL. See Endpoint Requirements below. | `"https://id.example.com/locid"` | +| params.ipEndpoint | Optional | String | Separate lightweight endpoint returning only the connection IP. Used for IP change detection without a full tx_cloc fetch. | `"https://id.example.com/ip"` | +| params.ipCacheTtlMs | Optional | Number | TTL for the IP cache entry in milliseconds. | `14400000` (4 hours, default) | | params.altId | Optional | String | Alternative identifier appended as `?alt_id=` query parameter. | `"user123"` | | params.timeoutMs | Optional | Number | Request timeout in milliseconds. | `800` (default) | | params.withCredentials | Optional | Boolean | Include credentials (cookies) on the request. | `false` (default) | @@ -164,6 +167,15 @@ The endpoint response contains: The module only uses `tx_cloc` for the EID. Any `stable_cloc` in the response is ignored client-side; it is available for proxy/endpoint operators to use in their own caching strategies. +### IP Change Detection + +The module uses a two-tier cache to detect IP changes without churning the tx_cloc identifier: + +- **IP cache** (default 4-hour TTL): Tracks the current connection IP in a separate localStorage key. +- **tx_cloc cache** (configured via `storage.expires`): Stores the LocID via Prebid's userId framework. + +When the IP cache expires, the module refreshes the IP. If `ipEndpoint` is configured, it makes a lightweight IP-only check first and only calls the main endpoint when the IP has changed. If the IP is unchanged and the tx_cloc cache is still valid, the existing tx_cloc is reused without calling the main endpoint. + ## EID Output When available, the LocID is included in the bid request as: From 313bf5cdba14d213616da5e72edcdb43fc0f354e Mon Sep 17 00:00:00 2001 From: Brian Date: Mon, 9 Feb 2026 10:52:36 -0600 Subject: [PATCH 5/5] Docs: remove LocID legacy 3384/GVL references and clarify atype 1 --- dev-docs/modules/userid-submodules/locid.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dev-docs/modules/userid-submodules/locid.md b/dev-docs/modules/userid-submodules/locid.md index 6772f7a3be..bdff732a7f 100644 --- a/dev-docs/modules/userid-submodules/locid.md +++ b/dev-docs/modules/userid-submodules/locid.md @@ -6,7 +6,6 @@ useridmodule: locIdSystem bidRequestUserId: locId eidsource: locid.com example: '"SYybozbTuRaZkgGqCD7L7EE0FncoNUcx-om4xTfhJt36TFIAES2tF1qPH"' -gvlid: 3384 --- ## Overview @@ -136,7 +135,7 @@ If `altId` is configured, the module appends it as `?alt_id=` to the endp ## Privacy Handling -LocID operates under Legitimate Interest (GVLID 3384). The module's privacy behavior depends on the configured privacy mode. +LocID operates under Legitimate Interest (LI). The module's privacy behavior depends on the configured privacy mode. ### Default Behavior (allowWithoutSignals) @@ -152,11 +151,11 @@ LocID operates under Legitimate Interest (GVLID 3384). The module's privacy beha When privacy signals are present, the module does not fetch or return an ID if any of the following apply: -- GDPR applies and vendor permission (GVLID 3384) is denied +- GDPR applies and vendorData is present, but consentString is missing or empty - US Privacy (CCPA) string indicates a processing restriction (third character is `Y`) - GPP signals indicate an applicable processing restriction -The module checks for vendor consent or legitimate interest for GVLID 3384 when GDPR applies and vendor data is available. +When GDPR applies and consentString is present, the module proceeds unless a framework processing restriction is signaled. ## Storage @@ -192,7 +191,7 @@ When available, the LocID is included in the bid request as: } ``` -The `atype` value of `1` indicates a device-based identifier per the OpenRTB 2.6 Extended Identifiers specification. +The `atype` value of `1` is the OpenRTB agent type for web environment; it is not an IAB GVL vendor ID. ## Debugging