layout | page_type | title | description | module_code | display_name | enable_download | sidebarType |
---|---|---|---|---|---|---|---|
page_v2 |
module |
Module - User ID |
Vendor-specific user ID sub-modules are available to support a range of identification approaches. |
userId |
User ID |
false |
1 |
{:.no_toc}
- TOC {:toc}
The User ID module supports multiple ways of establishing pseudonymous IDs for users, which is an important way of increasing the value of header bidding. Instead of having several exchanges sync IDs with dozens of demand sources, a publisher can choose to integrate with any of a number of ID schemes.
- The publisher determines which user ID modules to add to their Prebid.js package and consults with their legal counsel to determine the appropriate user disclosures.
- The publisher builds Prebid.js by specifying one or more ID sub-modules they would like to include. e.g. "gulp build --modules=____IdSystem". You also need to add the
userId
module to your Prebid.js distribution. - The page defines User ID configuration in
pbjs.setConfig()
- When
setConfig()
is called, and if the user has consented to storing IDs locally, the module is invoked to call the URL if needed- If the relevant local storage is present or the value of the id is specified in the configuration, the module doesn't call the URL and instead parses the scheme-dependent format, injecting the resulting ID into
bidRequest.userId
. - If GDPR applies, the consent signal from the CMP is hashed and stored in a cookie called
_pbjs_userid_consent_data
. Real-time consent is obtained from the CMP and compared to this value; if the user id is in storage and consent has not changed, the call to the id module may be suppressed to save network traffic. This functionality is provided so that ID sub-modules may be called to refresh their ID if the user's consent preferences have changed from the previous page, for example, the encryption of an id may need to change if the id provider learns it now has consent to share the id with a new DSP. If this value is suppressed by the strictStorageEnforcement, the id call will not be suppressed from refreshing for this reason but may be suppressed by other enforcement settings.
- If the relevant local storage is present or the value of the id is specified in the configuration, the module doesn't call the URL and instead parses the scheme-dependent format, injecting the resulting ID into
- An object containing one or more IDs (
bidRequest.userId
) is made available to Prebid.js adapters and Prebid Server S2S adapters. - In addition to
bidRequest.userId
,bidRequest.userIdAsEids
is made available to Prebid.js adapters and Prebid Server S2S adapters.bidRequest.userIdAsEids
has userIds in ORTB EIDS format. - The page can call pbjs.getUserIds(), pbjs.getUserIdsAsEids(), or pbjs.getUserIdsAsync().
{: .alert.alert-info :} Note that User IDs aren't as popular in the mobile app world because device ID is available in those ad serving scenarios.
{: .alert.alert-info :} Not all bidder adapters support all forms of user ID. See the tables below for a list of which bidders support which ID schemes.
When paired with the Consent Management module, privacy rules are enforced:
- The module checks the GDPR consent string
- If no consent string is available OR if the user has not consented to Purpose 1 (local storage):
- Calls to an external user ID vendor are not made.
- Nothing is stored to cookies or HTML5 local storage.
In addition, individual users may opt-out of receiving cookies and HTML5 local storage by setting these values:
_pbjs_id_optout
cookie or HTML5 local storage. The value can be anything -- if it exists, the user is considered opted out and no userId modules will fire._pubcid_optout
cookie or HTML5 local storage. This is for backwards compatibility with the original PubCommonID module, as of 5.0 known as the SharedId module. Likewise, the value can be anything.
Without third-party cookies, mechanisms like the NAI don't work, so some publishers may want to implement a first party opt-out so their users aren't tagged with first party cookies containing IDs.
Publishers that want to do this should design their workflow and then set _pbjs_id_optout
cookie or HTML5 local storage. For instance:
- read from an in-page javascript variable and set
_pbjs_id_optout
to any value. - call an in-page function and use the results to create a
_pbjs_id_optout
cookie with any value.
By including this module and one or more of the sub-modules, a number of new options become available in setConfig()
,
under the userSync
object as attributes of the userIds
array of sub-objects.
The value
parameter can be used to indicate an identifier the publisher has obtained via a direct integration with that identity provider that the publisher wishes to make available to Prebid.js bidders.
Publishers using Google AdManager may want to sync one of the identifiers as their Google PPID for frequency capping or reporting. The PPID in GAM (which is unrelated to the PPID UserId Submodule) has strict rules; refer to Google AdManager documentation for them. Please note, Prebid uses a GPT command to sync identifiers for publisher convenience. It doesn't currently work for instream video requests, as Prebid typically interacts with the player, which in turn may interact with IMA. IMA does has a similar method as GPT, but IMA does not gather this ID from GPT.
{: .table .table-bordered .table-striped }
Param under userSync | Scope | Type | Description | Example |
---|---|---|---|---|
ppid | Optional | String | Must be a source from the pbjs.getUserIdsAsEids() array | "pubcid.org" |
The table below has the options that are common across ID systems. See the sections below for specific configuration needed by each system and examples.
{% assign userid_pages = site.pages | where: "layout", "userid" | sort_natural: "title" %}
{% assign name_string = "" %} {% assign count = 0 %}
{: .table .table-bordered .table-striped }
Param under userSync.userIds[] | Scope | Type | Description | Example |
---|---|---|---|---|
name | Required | String | May be any of the following values: {% for page in userid_pages -%}{% if count == 1 %}{{ name_string │ append: ", " -}}{% endif %}{% assign count = 1 %}"{{ name_string │ append: name_string -}}{{ name_string │ append: page.useridmodule -}}" {% endfor %} |
"unifiedId" |
params | Based on User ID sub-module | Object | ||
bidders | Optional | Array of Strings | An array of bidder codes to which this user ID may be sent. | ['bidderA', 'bidderB'] |
storage | Optional | Object | The publisher can specify some kind of local storage in which to store the results of the call to get the user ID. This can be a cookie, HTML5 storage or both. | |
storage.type | Required | String | Must be "cookie" , "html5" or "cookie&html5" . This is where the results of the user ID will be stored. |
"cookie" |
storage.name | Required | String | The name of the cookie or html5 local storage where the user ID will be stored. | "_unifiedId" |
storage.expires | Strongly Recommended | Integer | How long (in days) the user ID information will be stored. If this parameter isn't specified, session cookies are used in cookie-mode, and local storage mode will create new IDs on every page. | 365 |
storage.refreshInSeconds | Optional | Integer | The amount of time (in seconds) the user ID should be cached in storage before calling the provider again to retrieve a potentially updated value for their user ID. If set, this value should equate to a time period less than the number of days defined in storage.expires . By default the ID will not be refreshed until it expires. |
30 |
value | Optional | Object | Used only if the page has a separate mechanism for storing a User ID. The value is an object containing the values to be sent to the adapters. | {"tdid": "1111", "IDP": "IDP-2233", "id5id": {"uid": "ID5-12345"}} |
Publishers can control which user ids are shared with the bid adapters they choose to work with by using the bidders array. The bidders array is part of the User id module config, publisher may choose to send an id to some bidders but not all, the default behavior is that each user id go to all bid adapters the publisher is working with.
Use the optional bidders
parameter to define an array of bidder codes to which this user ID may be sent.
In this example the SharedID sub adapter is only allowed to be sent to the Rubicon adapter.
userIds: [
{
name: "sharedId",
bidders: [
'rubicon'
],
params: {
syncTime: 60, // in seconds
defaultis24hours
},
storage: {
type: "cookie",
name: "sharedid",
expires: 28 // in days
}
}
]
The Rubicon bid adapter would then receive
{
"bidder": "rubicon",
// ...
"userId": {
"sharedid": {
"id": "01*******",
"third": "01E*******"
}
},
"userIdAsEids": [
{
"source": "sharedid.org",
"uids": [
{
"id": "01**********",
"atype": 1,
"ext": {
"third": "01***********"
}
}
]
}
],
// ...
}
It is possible for a user id submodule to populate several identifiers including identifiers that could also be populated by other user id submodules leading to collisions. In such cases of id collisions, it is possible to add a configurable prioritization to the core user id module. This will allow publishers to specify which user id submodule has priority for populating the identifier over other user id submodules.
This can be configured inside the userSync
object in the following manner:
Let's say that the UID2 token populated by the UID2 user ID submodule has the value 'uid2_value' and the UID2 token populated by Liveintent user id module has the value 'liveIntentUid2_value' (The actual identifiers populated in this case should be one and the same however the values are written differently in order to help the reader understand the source from which the identifiers get picked up from)
"userSync": {
"idPriority": {
"uid2": ['liveIntentId', 'uid2']
}
}
The corresponding user id object and the eids array will look like this:
{
// ...
"userId": {
"uid2": {
"id": "liveIntentUid2_value_98*******"
}
},
"userIdAsEids": [
{
"source": "uidapi.com",
"uids": [
{
"id": "liveIntentUid2_value_98*******",
"atype": 3,
"ext": {
"provider": "liveintent.com"
}
}
]
}
],
// ...
}
{% assign userid_pages = site.pages | where: "layout", "userid" | sort_natural: "title" %}
{% for page in userid_pages %}
If your ID structure is complicated, it is helpful to add tests for pbjs.getUserIds()
, pbjs.getUserIdsAsEids()
and pbjs.getUserIdsAsync()
.
To add a custom data type for the response of pbjs.getUserIdsAsEids()
, see other examples within the createEidsArray
method in /modules/userId/eid.js.
Bidders that want to support the User ID module in Prebid.js need to update their bidder adapter to read the indicated bidRequest attributes and pass them to their endpoint.
{: .table .table-bordered .table-striped }
| ID System Name | ID System Host | Prebid.js Attr: bidRequest.userId. | EID Source | Example Value |
| --- | --- | --- | --- | --- | --- |
| 33Across ID | 33Across | 33acrossId | 33across.com | "1111" |
| Admixer ID | Admixer | admixerId | admixer.net | "1111" |
| adQuery QiD | adQuery | qid | adquery.io | "p9v2dpnuckkzhuc..." |
| Adriver ID | Adriver | adriverId | adriver.ru | "1111" |
| Adtelligent ID | Adtelligent | adtelligentId | adtelligent.com | "1111"
|
| AMX ID | AMX | amxId | amxdt.net | "3ca11058-..." |
| BritePool ID | BritePool | britepoolid | britepool.com | "1111" |
| AudienceOne ID | DAC | dacId | dac.co.jp | {"id": "1111"} |
| DeepIntent ID | Deep Intent | deepintentId | deepintent.com | "1111" |
| DMD ID | DMD | dmdId | hcn.health | "1111" |
| ceeId | ceeId | ceeId | ceeid.eu | "111111" |
| Czech Ad ID | czechAdId | czechAdId | czechadid.cz | "1111" |
| CriteoID | Criteo | criteoId | criteo.com | "1111" |
| Fabrick ID | Neustar | fabrickId | neustar.biz | "1111" |
| FLoC ID | n/a | flocId | | |
| GrowthCode ID | GrowthCode | growthCodeId | growthcode.io | "1111" |
| Hadron ID | Audigent | hadronId | audigent.com | {"hadronId":"user-hadron-id", "auSeg":["segment1", "segment2"]} |
| ID+ | Zeotap | IDP | zeotap.com | "1111" |
| ID5 ID | ID5 | id5id | id5-sync.com | {uid: "1111", ext: { linkType: 2, abTestingControlGroup: false } } |
| IdentityLink | LiveRamp | idl_env | liveramp.com | "1111" |
| Intent IQ ID | Intent IQ | intentiqid | intentiq.com | "1111" |
| Kinesso ID | Kinesso | kpuid | kpuid.com | "1111" |
| LiveIntent ID | Live Intent | lipb.lipbid | liveintent.com | "1111" |
| Lotame Panorama ID | Lotame | lotamePanoramaId | crwdcntrl.net | "e4b9..." |
| MediaWallah OpenLink ID | MediaWallah | mwOpenLinkId | mediawallahscript.com | "1111" |
| merkleID | Merkle | merkleId | merkleinc.com | "1111" |
| naveggId | Navegg | naveggId | navegg.com | "1111" |
| netID | netID | netId | netid.de | "fH5A..." |
| Novatiq ID | Novatiq | novatiqId | novatiq.com | "1111" |
| Parrable ID | Parrable | parrableId | parrable.com | {"eid":"01.15946..."} |
| Publisher Link ID | n/a | publinkId | epsilon.com | |
| PubProvided ID | n/a | pubProvidedId | publisher domain | "1111" |
| Quantcast ID | n/a | quantcastId | quantcast.com | "1111" |
| Tapad ID | Tapad | tapadId | tapad.com | "1111" |
| Teads ID | Teads | teadsId | teads.com | "1111" |
| SharedID (PBJS 5.x) | n/a | pubcid | pubcid.org | "1111" |
| SharedID (PBJS 4.x)| Prebid | sharedid | sharedid.org | {"id":"01EAJWWN...", "third":"01EAJ..."} |
| Unified ID | Trade Desk | tdid | adserver.org | "1111" |
| ConnectID | Yahoo | connectId | yahoo.com | {"connectId": "72d04af6..."} |
| FreePass ID | FreePass | freepassId | | "1111" |
| UtiqMtp ID | Utiq | utiqMtpId | utiq-mtp.com | "1111" |
| Yandex ID | Yandex | yandexId | yandex.com | "11111111111111111" |
For example, the adapter code might do something like:
if (bidRequest.userId && bidRequest.userId.sharedid) {
url+="&pubcid="+bidRequest.userId.sharedid;
}
Bidders that want to support the User ID module in Prebid Server need to update their server-side bid adapter to read the desired OpenRTB 'user.ext.eids.source' object and forward the relevant values to their endpoint.
See the Prebid.js EIDs javascript source for the definitive list of user EID sources.
### Exporting User IDsIf you need to export the user IDs stored by Prebid User ID module, the getUserIds()
function will return an object formatted the same as bidRequest.userId.
pbjs.getUserIds() // returns object like bidRequest.userId. e.g. {"pubcid":"1111", "tdid":"2222"}
You can use getUserIdsAsEids()
to get the user IDs stored by Prebid User ID module in ORTB Eids format. Refer eids.md for output format.
pbjs.getUserIdsAsEids() // returns userIds in ORTB Eids format. e.g.
[
{
source: 'pubcid.org',
uids: [{
id: 'some-random-id-value',
atype: 1
}]
},
{
source: 'adserver.org',
uids: [{
id: 'some-random-id-value',
atype: 1,
ext: {
rtiPartner: 'TDID'
}
}]
},
{
source: 'id5-sync.com',
uids: [{
id: 'ID5-12345',
atype: 1,
ext: {
linkType: 2,
abTestingControlGroup: false
}
}]
}
]
pbjs.getUserIds()
and pbjs.getUserIdsAsEids()
may return only some IDs, or none at all, if they are called before all ID providers have had a chance to initialize - depending on auctionDelay
and/or syncDelay
, that may need to wait until an auction has completed.
To access the complete set of IDs, you may use getUserIdsAsync
, which returns a promise that is guaranteed to resolve only once all IDs are available:
pbjs.getUserIdsAsync().then(function (userIds) {
// all IDs are available here:
pbjs.getUserIds() // same as the `userIds` argument
pbjs.getUserIdsAsEids()
});
If you're an ID provider that wants to get on this page:
- Fork Prebid.js and write a sub-module similar to one of the *IdSystem modules already in the modules folder.
- Add your *IdSystem name into the modules/.submodules.json file
- Follow all the guidelines in the contribution page.
- Submit a Pull Request against the Prebid.js repository.
- Update the Prebid docs
- Fork the prebid.org documentation repository
- Add
/dev-docs/modules/userid-submodules/<userIdModuleName>.md
- Add a new row to
/dev-docs/modules/userId.md#prebidjs-adapters
- Submit a documentation Pull Request
Google now supports Encrypted Signals for Publishers(ESP), a program that allows publishers can explicitly share encrypted signals on bid requests with third-party bidders. User ID modules now support code which will register the signal sources and encrypted signals are created and are sent to GAM request in a3p parameter. 'encryptedSignal' configuration under userSync Module will help to configure signal sources.
Please find more details Share encrypted signals with bidders (Beta).
Alternatively, GAM can now pull IDs from Prebid for UserId submodules that register with GAM For those registered submodules, publishers can select Prebid UserID module (Beta) under "Signal collection deployment.". Publishers selecting this option should not also select those identifiers in the encryptedSignalSources.sources.source
array.
{: .table .table-bordered .table-striped }
Param under userSync | Scope | Type | Description | Example |
---|---|---|---|---|
encryptedSignalSources | Optional | Object | Publisher can specify the ESP config by adding encryptedSignal Object under userSync Object | |
encryptedSignalSources.sources | Required | Object | An array of Object consisting of a sources list and encryption flag | Check below config as an example |
encryptedSignalSources.sources.source | Required | Array | An array of sources for which signals needs to be registered | ['sharedid.org','criteo.com'] |
encryptedSignalSources.sources.encrypt | Required | Boolean | Should be set to false by default. Please find below note | true or false |
encryptedSignalSources.sources.customFunc | Required | function | This function will be defined for custom sources only and called which will return the custom data set from the page | Check below config as an example |
encryptedSignalSources.registerDelay | Optional | Integer | The amount of time (in milliseconds) after which registering of signals will happen. Default value 0 is considered if 'registerDelay' is not provided. | 3000 |
{: .alert.alert-info :} NOTE: For eids encryption (encryptedSignalSources.encrypt) set to true is not recommended unless downstream is informed of the changes.
{: .alert.alert-info :} NOTE: Publishers enabling passing eids/signal through ESP should reach out to SSPs integrated through OB to make sure to take any additional steps needed to ensure impact on 3p cookie based transaction is handled and impact is minimal.
ESP Configuration Example:
pbjs.setConfig({
userSync: {
...,
encryptedSignalSources: {
"sources": [{
source: ['sharedid.org', 'criteo.com', 'id5-sync.com', 'pubcid.org', 'audigent.com'],
encrypt: false
}, {
source: ['pubmatic.com'],
customFunc: () => {
return '{"keywords":["tech","auto"]}';
},
encrypt: true
}, {
source: ['segment.com'],
customFunc: () => {
return '[{ "id": "1", "value": "seg1" },{ "id": "2", "value": "seg2" }]';
},
encrypt: true
}],
"registerDelay": 3000
},
....
}
})
This will have no effect until you call the registerSignalSources
API. This method must be called
after the pbjs.setConfig
and gpt.js
has loaded. See API reference for registerSignalSources