Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated spec to reflect the changes for GPP API v1.1 and for IAB EU TCF v2.2 #70

Merged
merged 40 commits into from
Jun 27, 2023

Conversation

HeinzBaumann
Copy link
Collaborator

@HeinzBaumann HeinzBaumann commented Apr 11, 2023

Open for public comment until May 26th, 2023
Changes in this PR to support GPP API v1.1

  • Removed direct return values from all commands
  • Added callback support for all commands
  • Updated addEventHandler command to return initial EventListener response through callback instead of return value
  • Added success parameter to all callbacks
  • Fixed 2 typos in the sample stub code
  • Removed getGPPData command
  • Add new values to the eventName property in the EventListener object
  • Added new property in the pingReturn object with the same new values
  • Updated getSection output to array of objects

Changes in PR to support TCF 2.2:

  • Removal of legitimate interest for purposes 3-6
  • Removed getTCData command

@lamrowena lamrowena changed the title Updated spec to reflect the change coming in for IAB EU TCF v2.2 Updated spec to reflect the changes for GPP API v1.1 and for IAB EU TCF v2.2 May 1, 2023
@janwinkler
Copy link

While implementing the changes into our code, we found that the event order is not explizit enough, especially when vendors will start relying on "signalStatus" event. I'd therefore suggest to add some clarification to addEventListerner or another place.

Suggested text (please check & correct my english):

Event order
A CMP must send all approriate events and it must send them in a specific order so that listeners (e.g. vendors) can understand when a task has ended. Whenever the CMP starts to change or is about to change any of the existing sections or whenever the CMP is processing user input for an existing GPP string, it must always first set "signalStatus" to "not ready" and fire the corresponding event. It can then then perform the tasks (e.g. change the sections along with fireing the section change events). Only when all tasks are completed for the moment, the CMP can set the "signalStatus" to "ready" and fire the corresponding event. In other words: The event "signalStatus" shall always be the first (if applicable) and last in a chain of events being fired by the CMP.

Example 1:
The following example illustrates the events that being fired assuming support for IAB TCF Canada for a new visitor:

  1. (initial data of PingReturn is {gppVersion:1.1, cmpStatus: loading, cmpDisplayStatus: hidden, signalStatus: not ready, ... }
  2. listenerRegistered - CMP has registered the event listener, Event is immediatly fired after registering.
  3. cmpStatus - CMP is now loaded. Event is fired with name=cmpStatus and data=loaded
  4. cmpDisplayStatus - CMP now displays the consent layer. Event is fired with name=cmpDisplayStatus and data=visible
  5. (Visitor makes their choices and clicks on accept or reject or save)
  6. cmpDisplayStatus - CMP closed the consent layer and processes user input. Event is fired with name=cmpDisplayStatus and data=hidden
  7. sectionChange - CMP changes the section based on user input. Event is fired with name=sectionChange and data=tcfcav1
  8. (Note: If multiple sections are present, multiple sectionChange events may occur after another)
  9. signalStatus - CMP is done with the processing, vendors can use the data. Event is fired with name=signalStatus and data=ready

Example 2:
The following example illustrates the events that being fired assuming support for IAB TCF Canada for a returning visitor with a preexisting choice:

  1. (initial data of PingReturn is {gppVersion:1.1, cmpStatus: loading, cmpDisplayStatus: hidden, signalStatus: not ready, ... }
  2. listenerRegistered - CMP has registered the event listener, Event is immediatly fired after registering.
  3. cmpStatus - CMP is now loaded. Event is fired with name=cmpStatus and data=loaded
  4. signalStatus - CMP is done with the processing (consent information is loaded, no further processing needed, consent layer will not be shown), vendors can use the data. Event is fired with name=signalStatus and data=ready
  5. (User clicks on a link or button to re-surface the consent layer in order to change their choice
  6. signalStatus - CMP is expecting changes, vendors should not use the data but wait and pausetheir processing. Event is fired with name=signalStatus and data=not ready
  7. cmpDisplayStatus - CMP now displays the consent layer. Event is fired with name=cmpDisplayStatus and data=visible
  8. (Visitor makes their choices and clicks on accept or reject or save)
  9. cmpDisplayStatus - CMP closed the consent layer and processes user input. Event is fired with name=cmpDisplayStatus and data=hidden
  10. sectionChange - CMP changes the section based on user input. Event is fired with name=sectionChange and data=tcfcav1
  11. (Note: If multiple sections are present, multiple sectionChange events may occur after another)
  12. signalStatus - CMP is done with the processing, vendors can use the data. Event is fired with name=signalStatus and data=ready

@janwinkler
Copy link

  1. Clarification on addEventListerner data property for signalStatus missing: Please add "The data property will contain the new signalStatus value." to the table under EventListener Object.

  2. The second example at "Using the CMP API" is still using return values instead of callbacks.
    updated example code:

if(__gpp)
{
__gpp('addEventListener', function (evt)
{
//callback will receive all events, we only want to react on signalStatus ready events
if(evt.eventName !== 'signalStatus' || evt.data !== 'ready'){return ;}

//if only the TCString is needed, it get be taken directly from pingData.gppString
var gppString = evt.pingData.gppString;

//get the data from the TCF Canada section
__gpp('getSection',function(data, success)){
if(data === null){return ;}

var vendorConsent = data[0].VendorExpressConsent;
var vendorImpConsent = data[0].VendorImpliedConsent;
var purposeConsent = data[0].PurposesExpressConsent;
// ... do something Canadian !
}
}, 'tcfcav1');
}

  1. note that the above example does not work with TCF EU in the same way since we cant use getSection there. suggestion:
    Add "parsedSections" object to pingReturn. Description:
    The parsedSections property represents an object of all parsed sections of the gppString property that are supported by the API on this page (see supportedAPIs property). The object contains one property for each supported API with the name of the API as the property name and the value as a parsed representation of this section (similar to getSection command). If a section is supported but not represented in the gppString, it is omitted in the parsedSections object. Example:
    ...
    parsedSections: {tcfcav1: [{Version; 1 ...}, {...} ],
    tcfeuv2: [{Version: 2, ...}, {...} ],
    ... },
    ...

Copy link
Contributor

@patmmccann patmmccann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the references to tcfcav1 and tcfcav2 in this document appear incorrect according to

Core/CMP API Specification.md Show resolved Hide resolved
@patmmccann
Copy link
Contributor

as noted in the meeting, would be very helpful to see @janwinkler 's excellent parsedSections suggestion return parsedSections: {tcfcav1: [{SID : 5}, {Version; 1 ...}, {...} ], or something of that nature [ eg applicableAPIs], so maintaining sid to api maps will not be necessary for every api consumer.

@dgirardi
Copy link

While I like the parsedSections suggestion, I don't think it solves the problem of mapping from prefix to SID. It spares the necessity of calling getSection in a loop.

The other, hidden suggestion in @patmmccann comment would solve the mapping problem: include the SID in each section. Perhaps getSection could return something like this:

{
   sid: 7,
   api: "usnat",
   subSections: [
     /* Core Sub-section */
     {
      Version:1, 
      Created: Date (Thu Apr 13 2023 18:07:12 GMT+0200),
      LastUpdated: Date (Thu Apr 13 2023 18:07:12 GMT+0200),
      CmpId: 31, 
      CmpVersion: 123,
      ConsentScreen: 5,
      ...
      }, 
      /* Publisher Purposes Sub-section (optional) */
     {
      subsectionType:3, 
      PubPurposesExpressConsent : [1,2,3,4,5],
      PubPurposesImpliedConsent  : [6,7,8,9],
      ...
      } 
 ]
}

@janwinkler
Copy link

@dgirardi @patmmccann although im not against adding the section IDs, Im still not sure I understand the issue with the mapping:
If I as a vendor decide to support lets say US Nat., then I will anyway need to build a lot of custom logic (e.g. which fields to use and how). Adding a mapping "7=usnat" in my code doesnt seem too complicated ;-) And all other APIs/section IDs that are not mapped, i can simply ignore them (because my code wouldnt anyway know what to do with the data).

@patmmccann
Copy link
Contributor

patmmccann commented Jun 21, 2023

Adding a mapping "7=usnat" in my code doesnt seem too complicated ;-)

It isn't; the issue is maintaining the mapping. And as we see in #73 ; not even existing mappings can be considered stable. Publishers often take years to upgrade header bidding libraries. Prebid understanding a new mapping shouldn't require a software library upgrade. The cmp should present the mappings to its consumers.

@janwinkler
Copy link

@patmmccann But thats what i mean: once the mapping is created, it should never change (the recent changes i see more as a bug in the spec an not a real change). hence the only situation when you would need to update your mapping, is when you anyway work on your code to support a new legislation or new tcf version or something. anyhow, lets cut the conversation here and add the sid to the section and make us all happy ;-)

Fix Canada api name references in GPP 1.1
Added parsedSection to pingReturn object, updated the date referenced in applicableSections from July 1, 2023 to September 30, 2023.
parsedSections in pingReturn object
- Added section id to supportedAPIs
- Updated the code examples to match updated supportedAPIs
Updated supportedAPIs to include sectionid map
Added section id to supportedAPIs
Updated the code examples to match updated supportedAPIs
@patmmccann
Copy link
Contributor

Great work!

@@ -247,32 +248,6 @@ The publisher purposes segment is appended to the core segment by using the “.

# Client side API

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Client side API
# Client side API

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants