From 37a24fb90f391fcb6c8d0c4c6f0613cfd161213a Mon Sep 17 00:00:00 2001 From: jdwieland8282 Date: Fri, 16 Oct 2020 16:40:25 -0600 Subject: [PATCH 01/13] Create Id-Library.md Adding documentation for the Id Library module --- dev-docs/modules/Id-Library.md | 100 +++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 dev-docs/modules/Id-Library.md diff --git a/dev-docs/modules/Id-Library.md b/dev-docs/modules/Id-Library.md new file mode 100644 index 0000000000..c624d3d504 --- /dev/null +++ b/dev-docs/modules/Id-Library.md @@ -0,0 +1,100 @@ +--- +layout: page_v2 +page_type: module +title: ID Library +description: ID Graphing Adapter +module_code : currency +display_name : ID Library +enable_download : true +sidebarType : 1 +Maintainer: eng-dmp@magnite.com + +--- + + +# ID Library +{:.no_toc} + +The ID Library module gathers and generates a map of identities present on the page. The primary usecase for this adapter is for Publishers who have included multiple UserId subadapters in their prebid.js implementation, and want to store the resulting user ids serverside for modeling or graphing purposes. The ID Library module, anchors the response of `refreshUserIds()` to a presistant identifier (md5 encrypted) and returns an map of uids. This map of uids comes in the form of a POST message in JSON format and must be outputed to a publisher configured endpoint. + +A presistant identifier can be extraced in the following ways: + +1. From a generic `
` element +2. a publisher configured element, for example when configuration `target='username'`, the value is extracted from an element having id `'username'` +3. from the `` element of type text/email + +To get started add the module to your prebid.js wrapper + + +{: .alert.alert-info :} +gulp build --modules=idLibrary + + +## Application Flow + +In the idLibrary module, the presistant id is fetched from the page and synced with the user ids as follows: + +1. Checks for a valid configurations + 1. conf.url is a mandatory field + 1. conf.target and conf.debounce is optional field +1. If the configuration has conf.options.target, get the element with the target + 1. If valid entry (ex. email) exists in the target element, MD5 hash the value and get the user ids from user id module and post data to the configured url +1. If no valid value found, add an observer/listener on the element. + 1. Once the observer/listener finds a valid value, the value is MD5 hashed + 1. used ids are posted along side the resulting MD5 hash to the url provided + 1. listener is removed from the input element. +1. Check if the input element of type text/input has a valid email + 1. If the input listener gets a valid email, it is MD5 hashed + 1. used ids are posted along side the resulting MD5 hash to the url provided + 1. listener is removed from the input element. + 1. The mutation observer is called on every page reload and changes on the input element. Once the mutation observer finds a valid value in the body of the page, the hashed MD5 value and user ids are posted to configured url and mutation observer is disconnected from the body. + 1. If email is not found, add a listener on the input element and mutation observer on the body of the page + +![Image of IDLibrary](/assets/images/dev-docs/IDlib.png) + +## Configuration: + +| Param | Required | Description | +| --- | --- | --- | +| url | yes | The url endpoint is used to post the MD5 hasheds| +| target | no | Contains the element id from which the presistant value is to be read.| +| debounce | no | Time in milliseconds the module will wait before searching for the presistant value and user ids| + +## Example + +```javascript +pbjs.enableAnalytics([ + { + provider: 'detGraph', + options: { + url: 'url', + target: 'username', + debounce: 250 + } + } + ]); +``` + +### Post data format + +```json +{ + "hid": "MD5 hash", + "uids": "user ids array" +} +``` + +```json +{ + "hid":"5dd72a98c8146bafa84313fc15eb27c2", + "uids": + { + "id5id":"ID5-ZHMOQ7afBOa_gZxzTSelo5KFcVwCQgM7d-BUkWtjAA", + "sharedid": + { + "id":"01EE77EKRHXEZVJYMSQVRJ9536", + "third":"01EE77EKRHXEZVJYMSQVRJ9536" + } + } +} +``` From 497ec140ae02ded11ff8f254bb5a654340f49d90 Mon Sep 17 00:00:00 2001 From: bretg Date: Thu, 29 Oct 2020 16:14:52 -0400 Subject: [PATCH 02/13] fixing typos and configuration example --- dev-docs/modules/Id-Library.md | 52 ++++++++++++++++------------------ 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/dev-docs/modules/Id-Library.md b/dev-docs/modules/Id-Library.md index c624d3d504..9b2310a63e 100644 --- a/dev-docs/modules/Id-Library.md +++ b/dev-docs/modules/Id-Library.md @@ -15,16 +15,15 @@ Maintainer: eng-dmp@magnite.com # ID Library {:.no_toc} -The ID Library module gathers and generates a map of identities present on the page. The primary usecase for this adapter is for Publishers who have included multiple UserId subadapters in their prebid.js implementation, and want to store the resulting user ids serverside for modeling or graphing purposes. The ID Library module, anchors the response of `refreshUserIds()` to a presistant identifier (md5 encrypted) and returns an map of uids. This map of uids comes in the form of a POST message in JSON format and must be outputed to a publisher configured endpoint. +The ID Library module gathers and generates a map of identities present on the page. The primary usecase for this adapter is for Publishers who have included multiple UserId subadapters in their prebid.js implementation, and want to store the resulting user ids serverside for modeling or graphing purposes. The ID Library module, anchors the response of `refreshUserIds()` to a presistant identifier (md5 encrypted) and returns an map of uids. This map of uids comes in the form of a POST message in JSON format and must be output to a publisher configured endpoint. -A presistant identifier can be extraced in the following ways: +A persistant identifier can be extracted in the following ways: 1. From a generic `
` element -2. a publisher configured element, for example when configuration `target='username'`, the value is extracted from an element having id `'username'` -3. from the `` element of type text/email - -To get started add the module to your prebid.js wrapper +2. From a publisher configured HTML element id +3. From an `` element of type text/email +To get started, add the module to your prebid.js wrapper. From the command line: {: .alert.alert-info :} gulp build --modules=idLibrary @@ -32,18 +31,16 @@ gulp build --modules=idLibrary ## Application Flow -In the idLibrary module, the presistant id is fetched from the page and synced with the user ids as follows: - -1. Checks for a valid configurations - 1. conf.url is a mandatory field - 1. conf.target and conf.debounce is optional field -1. If the configuration has conf.options.target, get the element with the target - 1. If valid entry (ex. email) exists in the target element, MD5 hash the value and get the user ids from user id module and post data to the configured url -1. If no valid value found, add an observer/listener on the element. - 1. Once the observer/listener finds a valid value, the value is MD5 hashed - 1. used ids are posted along side the resulting MD5 hash to the url provided - 1. listener is removed from the input element. -1. Check if the input element of type text/input has a valid email +In the idLibrary module, the persistant id is fetched from the page and synced with the user ids as follows: + +1. Check for a valid configurations +1. If the configuration defines `target`, get the element with the named id + 1. If a valid entry (ex. email) exists in the target element, MD5 hash the value and get the user ids from user id module and post data to the configured url + 1. If no valid value is found, add an observer/listener on the element + 1. Once the observer/listener finds a valid value, the value is MD5 hashed + 1. used ids are posted along side the resulting MD5 hash to the url provided + 1. listener is removed from the input element +1. Else, check if an input element of type text/input has a valid email 1. If the input listener gets a valid email, it is MD5 hashed 1. used ids are posted along side the resulting MD5 hash to the url provided 1. listener is removed from the input element. @@ -63,20 +60,19 @@ In the idLibrary module, the presistant id is fetched from the page and synced w ## Example ```javascript -pbjs.enableAnalytics([ - { - provider: 'detGraph', - options: { - url: 'url', - target: 'username', - debounce: 250 - } - } - ]); + pbjs.setConfig({ + idLibrary:{ + url: 'url', + debounce: 250, + target: 'username' + } +}); ``` ### Post data format +After the data is collected, it will be POSTed to the configured URL in this format: + ```json { "hid": "MD5 hash", From 9c5e18fd18a6321a9d6ceb12ffc7f9d9176e0e9f Mon Sep 17 00:00:00 2001 From: jdwieland8282 Date: Thu, 29 Oct 2020 15:04:53 -0600 Subject: [PATCH 03/13] Update index.md adding reference to modules/index.html --- dev-docs/modules/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/dev-docs/modules/index.md b/dev-docs/modules/index.md index dd5b4bf164..7e387fad45 100644 --- a/dev-docs/modules/index.md +++ b/dev-docs/modules/index.md @@ -39,6 +39,7 @@ If you are looking for bidder adapter parameters, see [Bidders' Params]({{site.b | [**Advanced Size Mapping**](/dev-docs/modules/sizeMappingV2.html) | Display Responsive AdUnits in demanding page environments. | | [**Price Floors Module**](/dev-docs/modules/floors.html) | Configure and enforce minimum bids. | | [**GPT Pre-Auction Module**](/dev-docs/modules/gpt-pre-auction.html) | Adds a PB Ad Slot and matching GAM ad unit name to each ad unit's first-party data before bid requests are sent to the adapters. | +| [**ID Library**](/dev-docs/modules/id-library.html) | Retrieve user ids deployed on your site, and return them to a configurable endpoint for ID Graphing | ## Video Modules From f45432f2eb970ded1377fb026180e579d222acdf Mon Sep 17 00:00:00 2001 From: jdwieland8282 Date: Thu, 29 Oct 2020 15:44:59 -0600 Subject: [PATCH 04/13] Update Id-Library.md fixing typos --- dev-docs/modules/Id-Library.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-docs/modules/Id-Library.md b/dev-docs/modules/Id-Library.md index 9b2310a63e..1c97f1377e 100644 --- a/dev-docs/modules/Id-Library.md +++ b/dev-docs/modules/Id-Library.md @@ -37,14 +37,14 @@ In the idLibrary module, the persistant id is fetched from the page and synced w 1. If the configuration defines `target`, get the element with the named id 1. If a valid entry (ex. email) exists in the target element, MD5 hash the value and get the user ids from user id module and post data to the configured url 1. If no valid value is found, add an observer/listener on the element - 1. Once the observer/listener finds a valid value, the value is MD5 hashed + 1. once the observer/listener finds a valid value, the value is MD5 hashed 1. used ids are posted along side the resulting MD5 hash to the url provided 1. listener is removed from the input element 1. Else, check if an input element of type text/input has a valid email 1. If the input listener gets a valid email, it is MD5 hashed 1. used ids are posted along side the resulting MD5 hash to the url provided 1. listener is removed from the input element. - 1. The mutation observer is called on every page reload and changes on the input element. Once the mutation observer finds a valid value in the body of the page, the hashed MD5 value and user ids are posted to configured url and mutation observer is disconnected from the body. + 1. The mutation observer is called on every page reload and changes on the input element. Once the mutation observer finds a valid value in the body of the page, the hashed MD5 value and user ids are posted to url provided and mutation observer is disconnected from the body. 1. If email is not found, add a listener on the input element and mutation observer on the body of the page ![Image of IDLibrary](/assets/images/dev-docs/IDlib.png) From 662a5bb1f6ef6e1257711d6367f14b84b15e29e4 Mon Sep 17 00:00:00 2001 From: bretg Date: Mon, 2 Nov 2020 16:41:25 -0500 Subject: [PATCH 05/13] added image to PR, renamed file --- assets/images/dev-docs/IDlib.png | Bin 0 -> 45996 bytes .../modules/{Id-Library.md => idLibrary.md} | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/images/dev-docs/IDlib.png rename dev-docs/modules/{Id-Library.md => idLibrary.md} (100%) diff --git a/assets/images/dev-docs/IDlib.png b/assets/images/dev-docs/IDlib.png new file mode 100644 index 0000000000000000000000000000000000000000..b414ce5678688b9c44709f1f0b395737f24d0968 GIT binary patch literal 45996 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

O5y#!!pW_-gs2oxn<7cUMNd!Rw*r8!hqPyBEWq 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%0A)8-6+h^E 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 R&xnqJkNXl&=VC{0?4Mlg0A2t9 literal 0 HcmV?d00001 diff --git a/dev-docs/modules/Id-Library.md b/dev-docs/modules/idLibrary.md similarity index 100% rename from dev-docs/modules/Id-Library.md rename to dev-docs/modules/idLibrary.md From 56f39932da5c9ab335725b3ad764cf5447bd99b1 Mon Sep 17 00:00:00 2001 From: bretg Date: Mon, 2 Nov 2020 16:43:00 -0500 Subject: [PATCH 06/13] fixing module link to new filename --- dev-docs/modules/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-docs/modules/index.md b/dev-docs/modules/index.md index 7e387fad45..ea7aa18306 100644 --- a/dev-docs/modules/index.md +++ b/dev-docs/modules/index.md @@ -39,7 +39,7 @@ If you are looking for bidder adapter parameters, see [Bidders' Params]({{site.b | [**Advanced Size Mapping**](/dev-docs/modules/sizeMappingV2.html) | Display Responsive AdUnits in demanding page environments. | | [**Price Floors Module**](/dev-docs/modules/floors.html) | Configure and enforce minimum bids. | | [**GPT Pre-Auction Module**](/dev-docs/modules/gpt-pre-auction.html) | Adds a PB Ad Slot and matching GAM ad unit name to each ad unit's first-party data before bid requests are sent to the adapters. | -| [**ID Library**](/dev-docs/modules/id-library.html) | Retrieve user ids deployed on your site, and return them to a configurable endpoint for ID Graphing | +| [**ID Library**](/dev-docs/modules/idLibrary.html) | Retrieve user ids deployed on your site, and return them to a configurable endpoint for ID Graphing | ## Video Modules From 9e1d1076dc2fef2e4cf055a1977702a45914d2bf Mon Sep 17 00:00:00 2001 From: bretg Date: Mon, 2 Nov 2020 16:58:52 -0500 Subject: [PATCH 07/13] refining algorithm desc --- dev-docs/modules/idLibrary.md | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/dev-docs/modules/idLibrary.md b/dev-docs/modules/idLibrary.md index 1c97f1377e..6ae9d0b777 100644 --- a/dev-docs/modules/idLibrary.md +++ b/dev-docs/modules/idLibrary.md @@ -33,24 +33,20 @@ gulp build --modules=idLibrary In the idLibrary module, the persistant id is fetched from the page and synced with the user ids as follows: -1. Check for a valid configurations -1. If the configuration defines `target`, get the element with the named id - 1. If a valid entry (ex. email) exists in the target element, MD5 hash the value and get the user ids from user id module and post data to the configured url - 1. If no valid value is found, add an observer/listener on the element - 1. once the observer/listener finds a valid value, the value is MD5 hashed - 1. used ids are posted along side the resulting MD5 hash to the url provided - 1. listener is removed from the input element -1. Else, check if an input element of type text/input has a valid email - 1. If the input listener gets a valid email, it is MD5 hashed - 1. used ids are posted along side the resulting MD5 hash to the url provided - 1. listener is removed from the input element. - 1. The mutation observer is called on every page reload and changes on the input element. Once the mutation observer finds a valid value in the body of the page, the hashed MD5 value and user ids are posted to url provided and mutation observer is disconnected from the body. - 1. If email is not found, add a listener on the input element and mutation observer on the body of the page +1. Check for a valid 'idLibrary' configuration +1. If the configuration defines `target`, get the HTML element with the named id + 1. If a valid ID entry (e.g. email) exists in the target element, we're good, go on to step 5. + 1. Otherwise if no valid value is found, add a listener on the element + 1. Once the listener finds a valid value, go on to step 5. +1. Else, scan the values of all text and input elements on the page. If one of them has a valid persistent ID value, we found it. Go on to step 5. +1. Else, scan the whole body tag for a valid persistent ID value. If one is found go on to step 5. +1. If a valid persistent ID value has been found, then MD5 hash it, combine it with user IDs from the user ID module and POST to the specified endpoint. ![Image of IDLibrary](/assets/images/dev-docs/IDlib.png) ## Configuration: +{: .table .table-bordered .table-striped } | Param | Required | Description | | --- | --- | --- | | url | yes | The url endpoint is used to post the MD5 hasheds| From 725b5d73953a04b302f990e3cb26b4f3e68057ce Mon Sep 17 00:00:00 2001 From: jdwieland8282 Date: Mon, 2 Nov 2020 15:27:03 -0700 Subject: [PATCH 08/13] Update idLibrary.md --- dev-docs/modules/idLibrary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-docs/modules/idLibrary.md b/dev-docs/modules/idLibrary.md index 6ae9d0b777..6aae17b412 100644 --- a/dev-docs/modules/idLibrary.md +++ b/dev-docs/modules/idLibrary.md @@ -38,7 +38,7 @@ In the idLibrary module, the persistant id is fetched from the page and synced w 1. If a valid ID entry (e.g. email) exists in the target element, we're good, go on to step 5. 1. Otherwise if no valid value is found, add a listener on the element 1. Once the listener finds a valid value, go on to step 5. -1. Else, scan the values of all text and input elements on the page. If one of them has a valid persistent ID value, we found it. Go on to step 5. +1. Else, scan the values of all text and email input elements on the page. If one of them has a valid persistent ID value, we found it. Go on to step 5. 1. Else, scan the whole body tag for a valid persistent ID value. If one is found go on to step 5. 1. If a valid persistent ID value has been found, then MD5 hash it, combine it with user IDs from the user ID module and POST to the specified endpoint. From 4b544154a49fa4992929fde1b9b9d31721997cae Mon Sep 17 00:00:00 2001 From: jdwieland8282 Date: Mon, 2 Nov 2020 15:29:40 -0700 Subject: [PATCH 09/13] Update idLibrary.md --- dev-docs/modules/idLibrary.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dev-docs/modules/idLibrary.md b/dev-docs/modules/idLibrary.md index 6aae17b412..e70e333bca 100644 --- a/dev-docs/modules/idLibrary.md +++ b/dev-docs/modules/idLibrary.md @@ -19,9 +19,9 @@ The ID Library module gathers and generates a map of identities present on the p A persistant identifier can be extracted in the following ways: -1. From a generic `

` element -2. From a publisher configured HTML element id -3. From an `` element of type text/email +1. From a publisher defined target element +2. Searches for HTML input (text/email) element +3. Searches entire document for email using regex To get started, add the module to your prebid.js wrapper. From the command line: From a6b93b4ac919e2e50bb9202701e787083c949b03 Mon Sep 17 00:00:00 2001 From: jdwieland8282 Date: Mon, 2 Nov 2020 19:40:09 -0700 Subject: [PATCH 10/13] Update idLibrary.md removing unnecessary graphic --- dev-docs/modules/idLibrary.md | 1 - 1 file changed, 1 deletion(-) diff --git a/dev-docs/modules/idLibrary.md b/dev-docs/modules/idLibrary.md index e70e333bca..895e21358d 100644 --- a/dev-docs/modules/idLibrary.md +++ b/dev-docs/modules/idLibrary.md @@ -42,7 +42,6 @@ In the idLibrary module, the persistant id is fetched from the page and synced w 1. Else, scan the whole body tag for a valid persistent ID value. If one is found go on to step 5. 1. If a valid persistent ID value has been found, then MD5 hash it, combine it with user IDs from the user ID module and POST to the specified endpoint. -![Image of IDLibrary](/assets/images/dev-docs/IDlib.png) ## Configuration: From 1fa0cfcc1c001844824a82a895f7de470b958d5a Mon Sep 17 00:00:00 2001 From: bretg Date: Tue, 3 Nov 2020 13:56:50 -0500 Subject: [PATCH 11/13] wordsmithing --- dev-docs/modules/idLibrary.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dev-docs/modules/idLibrary.md b/dev-docs/modules/idLibrary.md index 895e21358d..990ad37dac 100644 --- a/dev-docs/modules/idLibrary.md +++ b/dev-docs/modules/idLibrary.md @@ -17,13 +17,13 @@ Maintainer: eng-dmp@magnite.com The ID Library module gathers and generates a map of identities present on the page. The primary usecase for this adapter is for Publishers who have included multiple UserId subadapters in their prebid.js implementation, and want to store the resulting user ids serverside for modeling or graphing purposes. The ID Library module, anchors the response of `refreshUserIds()` to a presistant identifier (md5 encrypted) and returns an map of uids. This map of uids comes in the form of a POST message in JSON format and must be output to a publisher configured endpoint. -A persistant identifier can be extracted in the following ways: +The module attempts to extract a persistant identifier in the following ways: 1. From a publisher defined target element 2. Searches for HTML input (text/email) element 3. Searches entire document for email using regex -To get started, add the module to your prebid.js wrapper. From the command line: +To get started, add the module to your Prebid.js wrapper. From the command line: {: .alert.alert-info :} gulp build --modules=idLibrary @@ -58,8 +58,8 @@ In the idLibrary module, the persistant id is fetched from the page and synced w pbjs.setConfig({ idLibrary:{ url: 'url', - debounce: 250, - target: 'username' + target: 'username', + debounce: 250 } }); ``` From 4b021e7112516e1166228cdd578f0f1e04e2142e Mon Sep 17 00:00:00 2001 From: jdwieland8282 Date: Tue, 3 Nov 2020 13:02:56 -0700 Subject: [PATCH 12/13] Update idLibrary.md Adding instructions on how to disable the full scan --- dev-docs/modules/idLibrary.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dev-docs/modules/idLibrary.md b/dev-docs/modules/idLibrary.md index 990ad37dac..8717116159 100644 --- a/dev-docs/modules/idLibrary.md +++ b/dev-docs/modules/idLibrary.md @@ -52,6 +52,8 @@ In the idLibrary module, the persistant id is fetched from the page and synced w | target | no | Contains the element id from which the presistant value is to be read.| | debounce | no | Time in milliseconds the module will wait before searching for the presistant value and user ids| +Please note, A full scan (step 4) of the body element is configured on by default but can be disabled by setting `"fullscan=false"` + ## Example ```javascript From b3d41c9bff67b02c4d0ad8aecd43f2a11dd9daea Mon Sep 17 00:00:00 2001 From: bretg Date: Tue, 3 Nov 2020 15:07:43 -0500 Subject: [PATCH 13/13] added fullscan to the config table --- dev-docs/modules/idLibrary.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dev-docs/modules/idLibrary.md b/dev-docs/modules/idLibrary.md index 8717116159..ea9bb9ea91 100644 --- a/dev-docs/modules/idLibrary.md +++ b/dev-docs/modules/idLibrary.md @@ -51,8 +51,9 @@ In the idLibrary module, the persistant id is fetched from the page and synced w | url | yes | The url endpoint is used to post the MD5 hasheds| | target | no | Contains the element id from which the presistant value is to be read.| | debounce | no | Time in milliseconds the module will wait before searching for the presistant value and user ids| +| fullscan | no | Allows the publisher to turn off the full page scan | -Please note, A full scan (step 4) of the body element is configured on by default but can be disabled by setting `"fullscan=false"` +Please note, A full scan (Step 4 above) of the body element is configured on by default but can be disabled by setting `"fullscan: false"` ## Example