diff --git a/ci/generate-documentation.ps1 b/ci/generate-documentation.ps1 index 42d212f2f..867e80160 100644 --- a/ci/generate-documentation.ps1 +++ b/ci/generate-documentation.ps1 @@ -23,6 +23,23 @@ Write-Host "::group::Cloning API docs" $env:GIT_LFS_SKIP_SMUDGE = 1 # use PR target branch if we're running in a PR, or the current CI branch, or main $ref = $env:GITHUB_BASE_REF ? $env:GITHUB_BASE_REF : $env:GITHUB_REF_NAME ? $env:GITHUB_REF_NAME : 'main' + +# An API repo is cloned at $ref where it has a branch of that name, so a +# documentation change can be previewed against the API change it describes. +# Where it has no such branch, main is used. Without the fallback the clone +# fails and the whole preview fails, which is what a documentation branch +# raised against another documentation branch always hits, because the name +# of a documentation branch means nothing in an API repo. +function Resolve-Ref($url, $preferred) { + if ($preferred -eq 'main') { + return 'main' + } + # ls-remote exits 0 with no output where the branch is absent, so the + # emptiness of the output is the test rather than the exit code. + $found = git ls-remote --heads $url $preferred + return $found ? $preferred : 'main' +} + $repoMap = & $PSScriptRoot/apis.ps1 # repos have to be cloned here since they expect documentation repo to be two levels above them $apis = New-Item -Force -ItemType Directory "apis" @@ -30,10 +47,18 @@ $apis = New-Item -Force -ItemType Directory "apis" New-Item -ItemType SymbolicLink -Force -Target $PWD -Path $apis/documentation | Out-Null foreach ($_ in $repoMap.GetEnumerator()) { $repo, $examples = $_.Key, $_.Value - git clone -b $ref --depth=1 --recurse-submodules --shallow-submodules "https://github.com/$env:GITHUB_REPOSITORY_OWNER/$repo.git" "$apis/$repo" + # Each repo is asked about on its own, because a branch can exist in one + # and not in the next, and an examples repo is a separate repo again. + $repoUrl = "https://github.com/$env:GITHUB_REPOSITORY_OWNER/$repo.git" + $repoRef = Resolve-Ref $repoUrl $ref + Write-Host "$repo at $repoRef" + git clone -b $repoRef --depth=1 --recurse-submodules --shallow-submodules $repoUrl "$apis/$repo" if ($examples) { # clone examples inside their main repo - git clone -b $ref --depth=1 "https://github.com/$env:GITHUB_REPOSITORY_OWNER/$examples.git" "$apis/$repo/$examples" + $examplesUrl = "https://github.com/$env:GITHUB_REPOSITORY_OWNER/$examples.git" + $examplesRef = Resolve-Ref $examplesUrl $ref + Write-Host "$examples at $examplesRef" + git clone -b $examplesRef --depth=1 $examplesUrl "$apis/$repo/$examples" } } Write-Host "::endgroup::" diff --git a/src/identifiers/fodid.md b/src/identifiers/fodid.md index 32b30c878..14e07d053 100644 --- a/src/identifiers/fodid.md +++ b/src/identifiers/fodid.md @@ -123,7 +123,7 @@ The block that does this is rendered into your script only when your Resource Ke ### The two sources, in order -1. **The 51Degrees Preference Management Platform**, if it is on the page. The script reads the answer in force through the platform's getter, listens for the platform's window event, and falls back to the platform's own stored answer. All three answers count, `non-marketing` included, and each is sent as a stated `id.usage`. See @ref Identifiers_PMP. +1. **The 51Degrees Preference Management Platform**, if it is on the page. The script reads the answer in force through the PMP's getter, listens for the PMP's window event, and falls back to the PMP's own stored answer. All three answers count, `non-marketing` included, and each is sent as a stated `id.usage`. See @ref Identifiers_PMP. 2. **A Transparency and Consent Framework consent management platform**, through `window.__tcfapi`. The script registers a listener at construction and takes the string from a callback reporting `tcloaded` or `useractioncomplete`, sending it as `tcstring`. See @ref Identifiers_PMP_CmpWiring. The first source that has an answer wins and the rest are ignored, and the cloud applies the same order when the request arrives. A Global Privacy Platform string is never read by either side, because the Model Terms for Marketing at do not map it. diff --git a/src/identifiers/fodid/gpp.md b/src/identifiers/fodid/gpp.md index 4ff54a75d..b7ca9c7e6 100644 --- a/src/identifiers/fodid/gpp.md +++ b/src/identifiers/fodid/gpp.md @@ -10,7 +10,7 @@ The Global Privacy Platform is the IAB Tech Lab container that carries several consent signals in one string, one section per signal. The US Privacy string is the older signal written for the California Consumer Privacy Act, which IAB Tech Lab deprecated on 31 January 2024 and tells its -users to replace with the platform. +users to replace with the Global Privacy Platform. # What Happens to a Request Carrying One @@ -41,11 +41,13 @@ Consent Framework's purposes onto standard marketing and personalized marketing, and maps no other signal, so a platform string can be a real signal and still say nothing a usage could be built from. -This is not a special case for the platform. A framework string that grants +This is not a special case for the Global Privacy Platform. A framework +string that grants too little for either usage produces no identifier either, for the same reason, which is that the signal does not say what the usage values say. -Mapping the platform needs a new version of the Model Terms and a cloud +Mapping the Global Privacy Platform needs a new version of the Model Terms +and a cloud release that reads it, so there is no setting on a resource key or a parameter on a request that turns this on. diff --git a/src/identifiers/fodid/pmp.md b/src/identifiers/fodid/pmp.md index 6b7279158..ac83b7c61 100644 --- a/src/identifiers/fodid/pmp.md +++ b/src/identifiers/fodid/pmp.md @@ -5,7 +5,7 @@ Terms for Marketing question and keeps the answer. That answer reaches the cloud as a stated `id.usage`, so the cloud works nothing out and the @ref Identifiers_51Did records that the usage was stated. -The platform itself, being the tag, the dialog and the shared answer, is +The PMP itself, being the tag, the dialog and the shared answer, is @ref Identifiers_PMP. This page is the part between the answer and the identifier. @@ -30,7 +30,7 @@ own environment. You write no code for this. -1. The visitor answers the dialog. The platform stores the answer, +1. The visitor answers the dialog. The PMP stores the answer, announces it on the window as a `51d-pmp-preference` event and holds it behind `window.__51d_pmp.preference()`. 2. The 51Degrees client script hears the announcement, or reads the getter @@ -40,12 +40,12 @@ You write no code for this. produced, so the identifier is created after everything else about the page is known. -The platform also serves a Transparency and Consent Framework surface of +The PMP also serves a Transparency and Consent Framework surface of its own, so the client script can see both an answer and a string on the -same page. The script asks the platform first and the framework second, and +same page. The script asks the PMP first and the framework second, and the cloud applies the same order when the request arrives, so the answer is what travels and the string beside it is never examined. That is why an -identifier made on a page running this platform records a stated usage. The +identifier made on a page running the PMP records a stated usage. The other order, where a string is all there is, is @ref Identifiers_51Did_Tcf. @@ -53,7 +53,7 @@ other order, where a string is all there is, is Bit 3 of the flags byte is the signal source bit, described under *Payload layout* on @ref Identifiers_51Did. It is clear on an identifier made from an -answer given to this platform, because the caller stated the usage, and set +answer given to the PMP, because the caller stated the usage, and set on one whose usage 51Degrees worked out from a consent string. The bit does not grade the two routes. It tells a recipient which one @@ -76,8 +76,8 @@ reading anything into how few identifiers a site produces. # Find Out More -- The platform, the dialog and the shared answer: @ref Identifiers_PMP -- How the platform compares with a consent management platform: +- The PMP, the dialog and the shared answer: @ref Identifiers_PMP +- How the PMP compares with a consent management platform: @ref Identifiers_PMP_CmpComparison - The three answers, where each is kept and how to read the one in force: @ref Identifiers_PMP_Preferences diff --git a/src/identifiers/fodid/tcf.md b/src/identifiers/fodid/tcf.md index eeac61d4a..a069bd2f4 100644 --- a/src/identifiers/fodid/tcf.md +++ b/src/identifiers/fodid/tcf.md @@ -6,9 +6,9 @@ records what a visitor consented to. The cloud reads that string, works out the usage of the @ref Identifiers_51Did from the purposes the string grants, and records inside the identifier that the usage came that way. -Putting the platform and the 51Degrees client script on a page is -@ref Identifiers_PMP_CmpWiring. This page is what the cloud does with the -string once it arrives. +Putting a consent management platform and the 51Degrees client script on +a page is @ref Identifiers_PMP_CmpWiring. This page is what the cloud does +with the string once it arrives. # Sending the String @@ -120,7 +120,8 @@ See *Usage policies and licensing* on @ref Identifiers_51Did. - IAB Europe, the Framework Policies, which say which purposes may be claimed under legitimate interest: -- IAB Tech Lab, the TC string format and the platform API: +- IAB Tech Lab, the TC string format and the consent management platform + API: - The client script that gathers the string: diff --git a/src/identifiers/pmp/cmp-comparison.md b/src/identifiers/pmp/cmp-comparison.md index a4f3220d0..a42ed734f 100644 --- a/src/identifiers/pmp/cmp-comparison.md +++ b/src/identifiers/pmp/cmp-comparison.md @@ -6,7 +6,7 @@ tags on your page as a consent management platform. It installs `window.__tcfapi`, the `__tcfapiLocator` frame and the cross frame message handler, and it hands out a TC string in the framework's format, so advertising code that already reads a consent management platform reads the -platform the same way. +PMP the same way. It does not follow the Transparency and Consent Framework Policies of IAB Europe. It is not registered with IAB Europe as a consent management @@ -19,8 +19,8 @@ What the answers to that question mean is set by the Model Terms for Marketing. The Model Terms prescribe, in Appendix 1, how the framework's purposes map onto the two marketing types, standard marketing and personalized marketing, and those two types are two of the three answers -the platform offers. The text in force is version 2, at -, and the platform's purpose sets are built from +the PMP offers. The text in force is version 2, at +, and the PMP's purpose sets are built from that appendix. The rest of the scheme, being who the parties are, what a receiver may do and why the protection is a contract rather than a property of the identifier, is in the explainer at , and this @@ -30,7 +30,7 @@ page does not repeat it. - IAB Europe, the Transparency and Consent Framework: -- IAB Europe, the Framework Policies, which the platform does not follow: +- IAB Europe, the Framework Policies, which the PMP does not follow: - IAB Europe, the framework for consent management platforms, which is where registration is described: @@ -47,22 +47,22 @@ page does not repeat it. - The Model Terms for Marketing explainer: -# The Platform Against a Consent Management Platform +# The PMP Against a Consent Management Platform | | A consent management platform under the Framework Policies | The Preference Management Platform | |---|---|---| -| Who sets the policy | IAB Europe, through the Transparency and Consent Framework Policies. | The Model Terms for Marketing, version 2. The platform follows the framework's technical schema and not its Policies. | -| Registration with IAB Europe | Required. IAB Europe's page for consent management platforms says that "CMPs must register to participate in the TCF", and a registered platform appears on the CMP list with a CMP ID of its own. | None. The platform is not registered and has no CMP ID of its own. It uses an ID chosen at random each day from IAB Europe's list of registered consent management platforms, writes that ID into the TC string and reports the same ID through `__tcfapi`. *The CMP ID* below gives the reason. | +| Who sets the policy | IAB Europe, through the Transparency and Consent Framework Policies. | The Model Terms for Marketing, version 2. The PMP follows the framework's technical schema and not its Policies. | +| Registration with IAB Europe | Required. IAB Europe's page for consent management platforms says that "CMPs must register to participate in the TCF", and a registered platform appears on the CMP list with a CMP ID of its own. | None. The PMP is not registered and has no CMP ID of its own. It uses an ID chosen at random each day from IAB Europe's list of registered consent management platforms, writes that ID into the TC string and reports the same ID through `__tcfapi`. *The CMP ID* below gives the reason. | | The question asked | Transparency and choices about the vendors the publisher has chosen to work with and the purposes each vendor wants to use, as IAB Europe's page for consent management platforms describes it. The Framework Policies say the choice on a purpose is to consent or to object, depending on the legal basis for the processing, and the CMP API specification says the Global Vendor List sets what must be disclosed to the visitor. | One question, in the visitor's own language, with up to three answers, being Personalized, Standard where you turn it on, and the alternative you configure. The purposes behind the two marketing answers are fixed by Appendix 1 of the Model Terms and the visitor does not pick among them. | -| Refusal | IAB Europe says the framework lets a user grant or withhold consent and object to processing. The CMP API specification has the platform capture those choices in a TC string and answer the scripts calling it with that string whenever the user has confirmed their choices. | There is no close cross and no reject button. The alternative button records `non-marketing`, which is an answer and not a refusal. No TC string is built for it, and the surface answers `getTCData` and `addEventListener` with `success` false until the visitor chooses Standard or Personalized. | -| Storage | Left to the platform. The TC string and vendor list formats specification, which the CMP API specification points to, says the storage used for a TC string is up to the consent management platform, cookie or not, and IAB Europe's page for consent management platforms says the same. In apps the CMP API specification names `IABTCF_TCString` and `IABTCF_gdprApplies`, among other keys, in `NSUserDefaults` or `SharedPreferences`. | The answer, one of three words, in this site's `localStorage` under `__51d_pmp_pref`, or in the cloud's own cookie when the visitor agrees to share it across your group. The TC string is built in memory from that answer on every page load and is never written to a cookie or to storage. | +| Refusal | IAB Europe says the framework lets a user grant or withhold consent and object to processing. The CMP API specification has the PMP capture those choices in a TC string and answer the scripts calling it with that string whenever the user has confirmed their choices. | There is no close cross and no reject button. The alternative button records `non-marketing`, which is an answer and not a refusal. No TC string is built for it, and the surface answers `getTCData` and `addEventListener` with `success` false until the visitor chooses Standard or Personalized. | +| Storage | Left to the PMP. The TC string and vendor list formats specification, which the CMP API specification points to, says the storage used for a TC string is up to the consent management platform, cookie or not, and IAB Europe's page for consent management platforms says the same. In apps the CMP API specification names `IABTCF_TCString` and `IABTCF_gdprApplies`, among other keys, in `NSUserDefaults` or `SharedPreferences`. | The answer, one of three words, in this site's `localStorage` under `__51d_pmp_pref`, or in the cloud's own cookie when the visitor agrees to share it across your group. The TC string is built in memory from that answer on every page load and is never written to a cookie or to storage. | | The identifier created | None of its own. On a page running a consent management platform the 51Degrees client script sends the TC string to the cloud, which derives the usage from the purposes granted, and the 51Did records that with the signal source bit set. | Every answer, `non-marketing` included, reaches the cloud as a stated `id.usage`, sent by the 51Degrees client script, and the 51Did records that the usage was stated directly, so the signal source bit is clear. | -| The legal basis of the answer | Consent or legitimate interests, which the Framework Policies name as the two lawful grounds under Article 6 of the General Data Protection Regulation that the framework supports. The CMP API specification has the platform obtain consent or register objections, and gives the framework's objective as helping everyone in the advertising chain comply with that Regulation and the ePrivacy Directive. | The Model Terms usage, which is a contract between the parties handling the identifier and not a consent under the Regulation. The dialog is shown whether or not the Regulation applies to the visit, and `gdprApplies` only changes what the surface reports. | -| What a vendor on the page receives | The TC string and the `TCData` object through `__tcfapi`, carrying that vendor's own consent and legitimate interest signals as the user set them. | The same surface and the same string format. The purpose consents come from the visitor's answer, the legitimate interest bits are set for purposes 2, 7, 8, 9, 10 and 11, and every vendor signal, special feature and publisher field is copied from the string you supply in `data-tcf-vendor` exactly as you encoded it. The platform decides nothing per vendor. | +| The legal basis of the answer | Consent or legitimate interests, which the Framework Policies name as the two lawful grounds under Article 6 of the General Data Protection Regulation that the framework supports. The CMP API specification has the PMP obtain consent or register objections, and gives the framework's objective as helping everyone in the advertising chain comply with that Regulation and the ePrivacy Directive. | The Model Terms usage, which is a contract between the parties handling the identifier and not a consent under the Regulation. The dialog is shown whether or not the Regulation applies to the visit, and `gdprApplies` only changes what the surface reports. | +| What a vendor on the page receives | The TC string and the `TCData` object through `__tcfapi`, carrying that vendor's own consent and legitimate interest signals as the user set them. | The same surface and the same string format. The purpose consents come from the visitor's answer, the legitimate interest bits are set for purposes 2, 7, 8, 9, 10 and 11, and every vendor signal, special feature and publisher field is copied from the string you supply in `data-tcf-vendor` exactly as you encoded it. The PMP decides nothing per vendor. | # The CMP ID -The platform is not registered with IAB Europe, so it has no CMP ID of its +The PMP is not registered with IAB Europe, so it has no CMP ID of its own. It uses an ID chosen at random each day from IAB Europe's list of registered consent management platforms, writes that ID into the TC string, and reports the same ID through `__tcfapi`. @@ -86,26 +86,26 @@ organisation that created it, and a receiver checks the signature against the public key that domain publishes. See @ref Identifiers_51Did and . -# Framework Features and How the Platform Implements Them +# Framework Features and How the PMP Implements Them | Feature of a consent management platform | How the Preference Management Platform implements it | |---|---| -| The `__tcfapi` stub that queues calls until the platform loads | Implemented. Installed when the bundle runs. `ping` is answered at once and every other call is queued until the string is ready, then answered in order. | +| The `__tcfapi` stub that queues calls until the PMP loads | Implemented. Installed when the bundle runs. `ping` is answered at once and every other call is queued until the string is ready, then answered in order. | | The `__tcfapiLocator` frame | Implemented. A hidden frame of that name is added to the body, or on `DOMContentLoaded` where the body is not parsed yet, and never added twice. | | Cross frame calls by `postMessage` | Implemented. A `__tcfapiCall` message is passed to `__tcfapi` and answered with a `__tcfapiReturn` message carrying the same `callId`. | -| `ping` | Implemented. Reports `cmpStatus`, `cmpLoaded`, `displayStatus`, `apiVersion` `2.3`, `cmpVersion` 1, `cmpId`, `gvlVersion`, `tcfPolicyVersion` and `gdprApplies`. | +| `ping` | Implemented. Reports `cmpStatus`, `cmpLoaded`, `displayStatus`, `apiVersion` `2`, `cmpVersion` 1, `cmpId`, `gvlVersion`, `tcfPolicyVersion` and `gdprApplies`. | | `addEventListener` | Implemented. A listener registered once the string is ready is called at once with `tcloaded`. One registered before that is called when the string becomes ready, and not straight away with a loading status. | | `removeEventListener` | Implemented, and still answered after the alternative answer, so a listener registered earlier can be taken off. | | `getTCData` | Implemented, although the specification deprecated the command in version 2.2. The purpose consents come from the visitor's answer and every other field is decoded from the string. | | `getVendorList` | Not implemented. Refused with `success` false. | -| `getInAppTCData` | Not implemented. The platform runs on web pages. | +| `getInAppTCData` | Not implemented. The PMP runs on web pages. | | Any other command | Refused with `success` false. | | Events | `tcloaded` when the string is ready, and again when `gdprApplies` changes. `useractioncomplete` on each answer. `cmpuishown` when the dialog is reopened while a string exists, so not on the first showing and not after the alternative answer. | | `gdprApplies` | Reported `true` until `IsGdpr` on the client script's object says otherwise, and a consumer already told `tcloaded` is told again with the corrected value. The dialog is shown either way. See @ref Identifiers_PMP_IsGdpr. | | CMP ID and CMP version | No ID of its own. An ID chosen at random each day from IAB Europe's list of registered consent management platforms, written into the string and reported by the surface, for the reason under *The CMP ID* above. `cmpVersion` is reported as 1 and the string's own version field is whatever `data-tcf-vendor` carries. | | Policy version and vendor list version | The `tcfPolicyVersion` and `vendorListVersion` read from the Global Vendor List when the bundle was built, reported by `ping` and `getTCData`. The string's own version fields are whatever `data-tcf-vendor` carries. | | The Global Vendor List | Not fetched at run time and not shown to the visitor. The build reads the list for the two version numbers and nothing else. | -| Vendors | Not chosen by the platform. Vendor consents, vendor legitimate interests and any disclosed vendors segment are copied from `data-tcf-vendor` unchanged. You generate that string with the framework's own tools to match the vendors you have contracted. | +| Vendors | Not chosen by the PMP. Vendor consents, vendor legitimate interests and any disclosed vendors segment are copied from `data-tcf-vendor` unchanged. You generate that string with the framework's own tools to match the vendors you have contracted. | | Purposes | Set from the answer, by Appendix 1 of the Model Terms. Standard consents to purposes 1, 2, 7, 8 and 11. Personalized consents to purposes 1, 2, 3, 4, 5, 6, 7, 8 and 11. Purposes 9, 10 and 12 are never consented. | | Legitimate interest | The bits for purposes 2, 7, 8, 9, 10 and 11 are set on both marketing answers, meaning no objection is recorded. There is no separate objection control. | | Special features and special purposes | Special feature opt-ins are copied from `data-tcf-vendor`. Special purposes carry no consent or objection signal in a TC string. | @@ -116,11 +116,11 @@ the public key that domain publishes. See @ref Identifiers_51Did and | Storing the TC string | Not stored. The string is rebuilt from the answer on every page load. | | A second layer with per purpose and per vendor controls, and stacks | Not implemented. The dialog offers the three answers and nothing per purpose or per vendor. | | Withdrawing or changing an answer | The bubble reopens the dialog at any time. A new answer is stored, a new string is built, and `useractioncomplete` follows. | -| One platform per page | The platform stops with a console warning when a `__tcfapi` that is not its own is already installed, and never replaces it. See @ref Identifiers_PMP_CmpWiring. | +| One PMP per page | The PMP stops with a console warning when a `__tcfapi` that is not its own is already installed, and never replaces it. See @ref Identifiers_PMP_CmpWiring. | # Find Out More -- Running a consent management platform instead of the platform: +- Running a consent management platform instead of the PMP: @ref Identifiers_PMP_CmpWiring - The three answers, where they are kept and how to read them: @ref Identifiers_PMP_Preferences diff --git a/src/identifiers/pmp/cmp-wiring.md b/src/identifiers/pmp/cmp-wiring.md index 05b6cf234..bfe2a93ed 100644 --- a/src/identifiers/pmp/cmp-wiring.md +++ b/src/identifiers/pmp/cmp-wiring.md @@ -32,7 +32,8 @@ The 51Degrees client script reads your consent management platform through Every consent management platform ships one, and the Framework's own specification already requires it to be first on the page. The stub queues anything asked of it. -- **The platform itself may load later.** That is the normal case and it +- **The consent management platform itself may load later.** That is the + normal case and it works, because the stub holds the registration until the real implementation takes over and then calls back. - **A missing stub has no recovery on that page view.** The client script @@ -138,9 +139,9 @@ is theirs and differs between vendors. @ref Identifiers_51Did_Tcf - The identifier, the usage values and how a consent string maps to one: @ref Identifiers_51Did -- The platform for a site that does not run a consent management platform: +- The PMP for a site that does not run a consent management platform: @ref Identifiers_PMP -- How the platform compares with a consent management platform, feature by +- How the PMP compares with a consent management platform, feature by feature: @ref Identifiers_PMP_CmpComparison - Header bidding with the identifier: @ref Integrations_Prebid - How the client script gathers page values: diff --git a/src/identifiers/pmp/configuration.md b/src/identifiers/pmp/configuration.md index ee3466a0c..e07f79ae2 100644 --- a/src/identifiers/pmp/configuration.md +++ b/src/identifiers/pmp/configuration.md @@ -1,57 +1,64 @@ @page Identifiers_PMP_Configuration Configuration Attributes -Every setting is a `data-` attribute on the one ` ``` -The platform's own URL names the loader and carries nothing else. Every -setting, the resource key included, is a `data-` attribute on the tag, so -each setting is written once and read from one place. The full list is on +The resource key is the file name in the PMP's own URL, which is the shape +every other keyed request takes, and it is read from there and from nowhere +else. Every other setting is a `data-` attribute on the tag, so each setting +is written once and read from one place. The full list is on @ref Identifiers_PMP_Configuration. +Up to 4.4.37 the key was the `data-resource-key` attribute and the URL was +`/api/v4/pmp` with nothing after it. Neither is served now. Two places to +write a key meant a page could carry one the cloud never saw, and the +refusal that followed was invisible to the page, so a tag in the old shape +is answered 404 on its first request instead. + Your resource key must be registered for the domain the page is served -from. The request for the platform's bundle is checked against the domains +from. The request for the PMP's bundle is checked against the domains the key names, the same as every other keyed endpoint, so a page on a domain the key does not cover is refused and no dialog appears. A page that suppresses the `Referer` header, with ` @@ -142,7 +162,7 @@ used, which is what almost every page wants. ``` -Every console message the platform writes names whichever object name is in +Every console message the PMP writes names whichever object name is in force, so a page using a different name reads messages about that name and not about `fod`. @@ -157,11 +177,11 @@ Use it for your own purposes, for example to tell your analytics that an answer was given. It is no longer how the client script is loaded. The client script hears the -answer through the platform's event and refreshes itself, so pointing the +answer through the PMP's event and refreshes itself, so pointing the action URL at the script's own URL would load a second copy of the script, which replaces the first and warns in the console. Where the action URL -names the cloud script and the object already exists, the platform skips it -for that reason. +names the cloud script and the client script's object is on the page or on +its way, the PMP skips it and says so in the console. Leaving `data-action-url` out means nothing is fired and nothing is written to the console. The answer is still stored, still announced, and the dialog @@ -198,7 +218,7 @@ is included only for a key that carries them too, so a page whose key has no - What the three answers mean and how to read the one in force: @ref Identifiers_PMP_Preferences -- Every attribute the platform reads: @ref Identifiers_PMP_Configuration +- Every attribute the PMP reads: @ref Identifiers_PMP_Configuration - Sharing an answer across your sites: @ref Identifiers_PMP_Sharing - The identifier the answer leads to: @ref Identifiers_51Did - How the client script gathers page values: @ref PipelineApi_Features_ClientSideEvidence diff --git a/src/identifiers/pmp/isgdpr.md b/src/identifiers/pmp/isgdpr.md index 4dfb66368..e486d0e7a 100644 --- a/src/identifiers/pmp/isgdpr.md +++ b/src/identifiers/pmp/isgdpr.md @@ -51,20 +51,20 @@ section is absent when the key does not request the property, so test that it is there before reading it. Do not carry that habit to the third party cookie result. The other value -the platform reads from the client script, +the PMP reads from the client script, `device.thirdpartycookiesenabled`, is a **string** carrying `'True'` or `'False'`, so a plain truth test on that one is wrong. See @ref Identifiers_PMP_Sharing. -# What the Platform Does With It +# What the PMP Does With It -At start up the platform reads `derived.isgdpr` from the client script's +At start up the PMP reads `derived.isgdpr` from the client script's object and sets `gdprApplies` on its own Framework surface from it. Where -your page carries no client script tag, the platform adds one, and where a -tag is there it waits for that tag to run, which is on -@ref Identifiers_PMP_Integration. +no client script object appears on your page by the time it has loaded, +the PMP adds a client script, and where one appears it reads that one, +which is on @ref Identifiers_PMP_Integration. -Where the value cannot be had, the platform writes a warning to the console +Where the value cannot be had, the PMP writes a warning to the console naming the reason, and leaves `gdprApplies` reporting `true`. Nothing else changes. The reason is one of three. @@ -76,7 +76,7 @@ changes. The reason is one of three. # The Dialog Is Shown Either Way **A `false` value does not stop the dialog and does not stop a 51Did being -created.** The question the platform asks is not a request for consent under +created.** The question the PMP asks is not a request for consent under the General Data Protection Regulation. It is the Model Terms for Marketing usage, which is a contractual question, and the answer is what a recipient of a 51Did is allowed to act on wherever the visitor is. `gdprApplies` is diff --git a/src/identifiers/pmp/preferences.md b/src/identifiers/pmp/preferences.md index 27dc67eb3..f079d210d 100644 --- a/src/identifiers/pmp/preferences.md +++ b/src/identifiers/pmp/preferences.md @@ -27,7 +27,7 @@ lets another site in your group offer its own alternative rather than asking a question the visitor has already answered. There is no fourth answer. The dialog has no close cross, so a visitor -cannot leave the first card unanswered, and the platform never invents an +cannot leave the first card unanswered, and the PMP never invents an answer on a visitor's behalf. # Where the Answer Is Kept @@ -43,7 +43,7 @@ and no stale copy to go wrong. Not confirmed covers a browser that blocks third party cookies, a result that is not known, and a confirmation that did not arrive within the three seconds -the platform waits, all set out on @ref Identifiers_PMP_Sharing. A write to the cloud that +the PMP waits, all set out on @ref Identifiers_PMP_Sharing. A write to the cloud that is refused, or not confirmed within 1500 milliseconds, also leaves the answer in this site's `localStorage`. @@ -79,7 +79,7 @@ answer lives here, and where the answer moved to the group's shared store the cloud's cookie has to go as well, which @ref Identifiers_PMP_Sharing describes. -Reopening the dialog does not need a reload. Call the platform's own method +Reopening the dialog does not need a reload. Call the PMP's own method and the visitor gets the dialog back with their current answer shown. ```{js} @@ -89,7 +89,7 @@ window.__51d_pmp.open(); # Reading the Answer From Your Page There are three ways in, and they exist because a page cannot know whether -the platform's bundle has loaded yet. +the PMP's bundle has loaded yet. ## The Window Event @@ -105,7 +105,7 @@ window.addEventListener('51d-pmp-preference', function (e) { }); ``` -Register the listener before the platform's tag if you can. The event fires +Register the listener before the PMP's tag if you can. The event fires once per answer coming into force, so a listener registered afterwards can miss the announcement and should read the getter as well. @@ -116,13 +116,13 @@ var answer = window.__51d_pmp && window.__51d_pmp.preference(); // 'standard', 'personalized', 'non-marketing', or null when nobody has answered ``` -The getter answers from memory, straight away, with whatever the platform +The getter answers from memory, straight away, with whatever the PMP found when it started, this site's storage and the group's shared answer included. The object exists only once the bundle has loaded, so test for it. ## The Transparency and Consent Framework Surface -The platform exposes a `window.__tcfapi` function, which is how advertising +The PMP exposes a `window.__tcfapi` function, which is how advertising code on the page normally asks about consent, and it answers the standard `ping`, `getTCData`, `addEventListener` and `removeEventListener` commands. @@ -135,7 +135,7 @@ __tcfapi('addEventListener', 2, function (tcData, success) { ``` The string it hands out is built from the vendor string you supply in -`data-tcf-vendor`. The platform sets the purpose bits from the visitor's +`data-tcf-vendor`. The PMP sets the purpose bits from the visitor's answer and the time fields, and copies everything else through unchanged, so a validator sees your own vendor set exactly as you encoded it. @@ -147,13 +147,13 @@ so a validator sees your own vendor set exactly as you encoded it. After the alternative answer the surface answers `addEventListener` and `getTCData` with `success` false, and `ping` reports that no string is loaded. That is only the framework's way of describing an answer that grants -no purposes, and it is not the platform failing and not the visitor +no purposes, and it is not the PMP failing and not the visitor declining to answer. The 51Degrees client script never reads that as the -answer, because it takes the answer from the platform itself, where +answer, because it takes the answer from the PMP itself, where `non-marketing` is a value like any other. Choosing Standard or Personalized afterwards restores the full surface. -# The Platform Is Not a Consent Management Platform +# The PMP Is Not a Consent Management Platform The Preference Management Platform is a technically complete implementation of the Transparency and Consent Framework, and it deliberately does not @@ -162,7 +162,7 @@ about the Model Terms usages. So a site that runs a consent management platform does not add this one. The two never share a page, they would fight over `window.__tcfapi`, and -the platform stops with a console warning when it finds a foreign +the PMP stops with a console warning when it finds a foreign `__tcfapi` already installed rather than replacing it. Where the Framework's Policies are what you need, run a consent management platform and wire the 51Degrees client script to it instead, which is @@ -171,7 +171,7 @@ Policies are what you need, run a consent management platform and wire the # Changing an Answer A visitor can reopen the dialog from the bubble at any time and answer -differently. When they do, the platform announces the new answer, the +differently. When they do, the PMP announces the new answer, the 51Degrees client script asks the cloud again, and a fresh 51Did is created carrying the new usage. Page code registered through the client script's `onChange` callback is called with the new data. The identifier issued @@ -185,7 +185,7 @@ of them is what the Model Terms say. - Carrying one answer across your sites: @ref Identifiers_PMP_Sharing - Running a consent management platform instead: @ref Identifiers_PMP_CmpWiring -- How the platform compares with a consent management platform, feature by +- How the PMP compares with a consent management platform, feature by feature: @ref Identifiers_PMP_CmpComparison - What to tell your visitors in your privacy notice: @ref Identifiers_PMP_Privacy diff --git a/src/identifiers/pmp/privacy.md b/src/identifiers/pmp/privacy.md index bc68dc974..1bf459756 100644 --- a/src/identifiers/pmp/privacy.md +++ b/src/identifiers/pmp/privacy.md @@ -3,8 +3,8 @@ diff --git a/src/identifiers/pmp/sharing.md b/src/identifiers/pmp/sharing.md index d0370eb57..a024c40e0 100644 --- a/src/identifiers/pmp/sharing.md +++ b/src/identifiers/pmp/sharing.md @@ -4,7 +4,7 @@ A visitor who has answered on one of your websites should not have to answer again on the next one. The Preference Management Platform can offer to carry one answer across a group of sites you name, so the question is asked once. -This is a feature of this platform. A site running a third party consent +This is a feature of the PMP. A site running a third party consent management platform neither reads nor writes the shared answer and never sees the second card. Nothing stops another vendor implementing the same exchange, because the endpoint and the rules are described here. @@ -42,7 +42,7 @@ The second card is offered when all three of these hold. 51Degrees client script confirms them by testing the cookie, and only a tested `'True'` counts. A `'False'`, a result that is not known, the likely status the script starts with and no result at all each mean no - second card. For the platform to have a tested result, your resource key + second card. For the PMP to have a tested result, your resource key has to carry `ThirdPartyCookiesEnabled` and `ThirdPartyCookiesEnabledJavaScript` beside it, so a key missing either one never shows the second card, and the console names the missing @@ -55,21 +55,27 @@ being answered, and clicking it goes back. ## When the Second Card Waits **When your configuration allows third party cookies and the browser may -support them, the platform waits up to three seconds (3000 milliseconds) +support them, the PMP waits up to three seconds (3000 milliseconds) for the 51Degrees client script to confirm that third party cookies work. If they are not confirmed in that time, the second card is not shown and the answer stays with this site.** -The three seconds start when the visitor answers the first card. The waiting +The three seconds start at the later of the visitor's answer and a client +script being on the page, whether your own or one the PMP added, because +nothing measures the cookie until one is there. On a page that already has +a client script when the visitor answers, which is the ordinary case, that +is the moment of the answer. On a page still loading it is when the script +arrives, so the ring can be up for the wait for the script and then these +three seconds, one after the other. The waiting ring covers the cards for as long as the wait lasts, and while it does the cards are darkened and nothing on them can be pressed. The time is set once -when the platform is built, it is the same on every page, and no attribute +when the PMP is built, it is the same on every page, and no attribute changes it.