Date | Version | Comments |
Sept 28, 2022 | 1.0 |
Published final public version |
Nov 3, 2023 | 1.0 |
Added clarifications to encoding mechanism, fixed encoded header examples |
This document is one of the IAB Tech Lab Global Privacy Platform Specifications. It defines the technical implementation of the structure and encoding for a Global Privacy Platform String (GPP String).
Updates were made to existing IAB Tech Lab standards to support the Global Privacy Platform. These updates are based on industry consensus, driven by relevant IAB Tech Lab working groups, including the Global Privacy Working Group and Programmatic Supply Chain Working Group. They include:
OpenRTB Attributes:
GPP assumes the use of OpenRTB 2.x.
- Like other existing privacy signals (TCF and USPrivacy), the GPP string is also able to be transported via OpenRTB. This will be included in the Regs object in the November 2022 release. See this document for approved design prior to release.
The Global Privacy Platform (GPP) enables advertisers, publishers and technology vendors in the digital advertising industry to adapt to regulatory demands across markets. It is a single protocol designed to streamline transmitting privacy, consent, and consumer choice signals from sites and apps to ad tech providers. IAB Tech Lab stewards the development of these technical specifications.
The IAB Technology Laboratory (Tech Lab) is a non-profit consortium that engages a member community globally to develop foundational technology and standards that enable growth and trust in the digital media ecosystem. Comprised of digital publishers, ad technology firms, agencies, marketers, and other member companies, IAB Tech Lab focuses on improving the digital advertising supply chain, measurement, and consumer experiences, while promoting responsible use of data. Its work includes the OpenRTB real-time bidding protocol, ads.txt anti-fraud specification, Open Measurement SDK for viewability and verification, VAST video specification, and DigiTrust identity service. Established in 2014, the IAB Tech Lab is headquartered in New York City with staff in San Francisco, Seattle, and London. Learn more at iabtechlab.com.
Contributors and Technical Governance
IAB Tech Lab's Global Privacy Working Group members provide contributions to this repository. Participants in the Global Privacy Working group must be members of IAB Tech Lab. Technical Governance for the project is provided by the IAB Tech Lab Privacy & Rearc Commit Group.
License
Global Privacy Platform technical specifications governed by the IAB Tech Lab is licensed under a Creative Commons Attribution 3.0 License. To view a copy of this license, visit creativecommons.org/licenses/by/3.0/ or write to Creative Commons, 171 Second Street, Suite 300, San Francisco, CA 94105, USA.
Disclaimer
THE STANDARDS, THE SPECIFICATIONS, THE MEASUREMENT GUIDELINES, AND ANY OTHER MATERIALS OR SERVICES PROVIDED TO OR USED BY YOU HEREUNDER (THE “PRODUCTS AND SERVICES”) ARE PROVIDED “AS IS” AND “AS AVAILABLE,” AND IAB TECHNOLOGY LABORATORY, INC. (“TECH LAB”) MAKES NO WARRANTY WITH RESPECT TO THE SAME AND HEREBY DISCLAIMS ANY AND ALL EXPRESS, IMPLIED, OR STATUTORY WARRANTIES, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AVAILABILITY, ERROR-FREE OR UNINTERRUPTED OPERATION, AND ANY WARRANTIES ARISING FROM A COURSE OF DEALING, COURSE OF PERFORMANCE, OR USAGE OF TRADE. TO THE EXTENT THAT TECH LAB MAY NOT AS A MATTER OF APPLICABLE LAW DISCLAIM ANY IMPLIED WARRANTY, THE SCOPE AND DURATION OF SUCH WARRANTY WILL BE THE MINIMUM PERMITTED UNDER SUCH LAW. THE PRODUCTS AND SERVICES DO NOT CONSTITUTE BUSINESS OR LEGAL ADVICE. TECH LAB DOES NOT WARRANT THAT THE PRODUCTS AND SERVICES PROVIDED TO OR USED BY YOU HEREUNDER SHALL CAUSE YOU AND/OR YOUR PRODUCTS OR SERVICES TO BE IN COMPLIANCE WITH ANY APPLICABLE LAWS, REGULATIONS, OR SELF-REGULATORY FRAMEWORKS, AND YOU ARE SOLELY RESPONSIBLE FOR COMPLIANCE WITH THE SAME.
In the GPP, a GPP String is used to encapsulate relevant details about transparency and consumer choice and encoded as it applies for each supported regional or other signal. This document specifies how that string must be formatted and how it must be used.
A GPP String’s primary purpose is to encapsulate and encode all the information disclosed to a user and the expression of their choices, for all applicable regions. Using a Consent Management Platform (CMP), the information is captured into an encoded and compact HTTP-transferable string. This string enables communication of the consumer's choices from sites and apps to ad tech providers. Ad tech providers decode a GPP String to determine whether they have the necessary requirements to process a user’s personal data for their purposes.
Version 1 of the GPP String contains the following information:
- User disclosures and choices: Disclosures to and control by the user, with a given granularity dependent on jurisdictional and policy requirements (by-purpose, by-vendor, by-legal-basis, or “omnibus” all or nothing)
- General metadata: context of the choices including timestamps, versions, CMP info, locales, publisher info, regional or jurisdictional applicability
- Restrictions: possible additional legal, publisher, or framework restrictions
Section specifications will clearly define which of the above data are represented, and in what form.
See “Discrete Sections” below for more detail.
Digital property owners or CMPs are responsible for generating, persisting, and passing the GPP String. Vendors or any other third-party service providers must neither create nor alter GPP Strings.
There are cases in existing privacy signals where strings are too long for certain applications. Since the GPP expects additional discrete sections to be added, it is reasonable to expect that string length will continue to be a concern. To optimize this, we look to Fibonacci coding.
About Fibonacci Encoding
In simple terms, Fibonacci numbers are numbers that are the combination of the two Fibonacci numbers that come before. The numbers are [excluding 0, 1,] 1 (0+1), 2 (1+1), 3 (1+2), 5 (2+3), 8 (5+3), 13 (5+8), and so on... The numbers can be converted into bit sequences that are unique and will always end on “11”. E.g. the bit representation of the first Fibonacci numbers are:
Number | Fibonacci representation | Bit sequence |
1 |
F(2) | 11 |
2 |
F(3) | 011 |
3 |
F(4) | 0011 |
4 |
F(2) + F(4) | 1011 |
5 |
F(5) | 00011 |
6 |
F(2) + F(5) | 10011 |
7 |
F(3) + F(5) | 01011 |
The advantage of this is, that a sequence of numbers can be encoded into a sequence of bits without the need to know the length of the bit sequences in advance. This, therefore, saves a lot of bits (size), in the case of TCF it especially saves size when encoding numbers that are around 100 to 4000.
Encoding and Decoding
The encoding and decoding is simple and can be done in basically all development languages.
(From Wikipedia)
To encode an integer N:
- Find the largest Fibonacci number equal to or less than N; subtract this number from N, keeping track of the remainder.
- If the number subtracted was the i-th Fibonacci number F(i), put a 1 in place i−2 in the code word (counting the left-most digit as place 0).
- Repeat the previous steps, substituting the remainder for N, until a remainder of 0 is reached.
- Place an additional 1 after the rightmost digit in the code word.
To decode a code word, remove the final "1", assign the remaining values 1,2,3,5,8,13... (the Fibonacci numbers) to the bits in the code word, and sum the values of the "1" bits.
The following details provide information on creating, storing, and managing a GPP String. The basic steps for creating a GPP String are as follows:
- Create discrete sections.
- For sections that use the recommended encoding mechanism:
- Create a bit representation of the section's header (if it exists).
- Add padding (0) on the right to get to a total bit length that is a multiple of 6 bits.
- To convert the bit sequence into strings, start by taking each 6 bits, convert the 6 bits into an integer, and use this integer as the index of the character in the table below.
- Concatenate the header to the sub-sections using the "." (dot) character.
- For sections that use a different encoding mechanism, ensure that the data is websafe and does not include the “~” (tilde) character or the "." (dot) character.
- For sections that use the recommended encoding mechanism:
- Create header section. See examples of the header section below.
- Create a bit representation of the GPP header section including all Section IDs for discrete sections in a sorted order.
- Add padding (0) on the right to get to a total bit length that is a multiple of 6 bits.
- Convert the integer to convert the six bit sequence into a character where the integer is the index of the character in the table below.
- Concatenate all sections. Concatenate the encoded GPP header as the first item to the encoded versions of the discrete sections using “~” (tilde) as the delimiter. See examples of GPP strings below.
Note that neither the header nor the recommended encoding mechanism for a discrete section utilizes base64 encoding but rather a modified version of it.
Value | Encoding | Value | Encoding | Value | Encoding | Value | Encoding |
0 | A | 17 | R | 34 | i | 51 | z |
1 | B | 18 | S | 35 | j | 52 | 0 |
2 | C | 19 | T | 36 | k | 53 | 1 |
3 | D | 20 | U | 37 | l | 54 | 2 |
4 | E | 21 | V | 38 | m | 55 | 3 |
5 | F | 22 | W | 39 | n | 56 | 4 |
6 | G | 23 | X | 40 | o | 57 | 5 |
7 | H | 24 | Y | 41 | p | 58 | 6 |
8 | I | 25 | Z | 42 | q | 59 | 7 |
9 | J | 26 | a | 43 | r | 60 | 8 |
10 | K | 27 | b | 44 | s | 61 | 9 |
11 | L | 28 | c | 45 | t | 62 | + |
12 | M | 29 | d | 46 | u | 63 | / |
13 | N | 30 | e | 47 | v | ||
14 | O | 31 | f | 48 | w | (pad) | = |
15 | P | 32 | g | 49 | x | ||
16 | Q | 33 | h | 50 | y |
The storage mechanism used for GPP Strings is up to a CMP, including any non-cookie storage mechanism.
The GPP string is comprised of distinct sections joined together on a “~” (tilde) character.
The string must contain a header and applicable discrete section(s): [Header]~[Discrete Section]
The header is always required and comes first. The purpose of the Header is to identify which sections are included in a string payload and be a table of contents of where to find each signal in the string payload (broken into discrete sections). It is basically an ordered list of discrete sections that equate to different regions, countries or policies. It lets readers understand what is present in the string and in what order. (See Discrete Sections below)
The header contains only a GPP version, the section ID(s) and index of the place of the associated section in the string. The header delegates regional policy versions and technical encoding versions to each substring section so that each may develop independently of each other and the header design. (See Discrete Sections below)
For the full list of Section IDs, see Section information.
The Header is always required and always comes first. It consists of the following encoded fields and uses Fibonacci encoding. For more information about Fibonacci Encoding, see the “About Fibonacci Encoding” section.
Position | Type | Description |
Type |
Int(6) | Fixed to 3 as “GPP Header field” |
Version |
Int(6) | Version of the GPP spec (currently 1) |
Sections |
Range(Fibonacci) | List of Section IDs that are contained in the GPP string. Each ID represents a discrete section that will be concatenated to the Header Section. The IDs must be represented in the order the related sections appear in the string. This is required to make real-time string processing less resource intensive. |
Header Example 1 |
Conditions:
|
Header Bit Representation
|
Full header bit string with padding: 000011 000001 000000 000001 001100 |
Encoded header: DBABM |
Header Example 2 |
Conditions:
|
Header Bit Representation
|
Full header bit string with padding: 000011 000001 000000 000010 001101 011000 |
Encoded header: DBACNY |
Header Example 3
Header Example 3 |
Conditions:
|
Bit Representation
Data Types table for more detail on these fields. |
Full bit string with padding: 000011 000001 000000 000001 100011 110000 |
Encoded header: DBABjw |
Discrete sections are used to support multiple signals from one architecture while maintaining the ability to modify each section as needed.
Each string section is scoped to the same body that updates the spec. This allows for regional sovereignty policies to make changes that might include more delimited information. For example, if TCF needs a version 3 and eliminates the concept of “out of band” vendors—which would result in the removal of DisclosedVendors and AllowedVendors—that should not require a version bump to the GPP string specification.
In order to be backward compatible with IAB Europe’s TC String and US Privacy String formats, the delimiter used to separate sections is “~” (tilde).
Note: URL-safe characters are important to meet the integration needs of those not reading privacy signals server side or via the client-side APIs. URL-safe characters are:
- A-Z, a-z, 0-9
- – (minus)
- . (dot)
- _ (underscore)
- ~ (tilde)
“.” and “-” and “_” are in use which leaves “~” as the only possible delimiter unless we re-use “.”.
A discrete section is encoded according to that specific section’s needs. This means today’s implementations that read and adapt to TCF v2.0 signals or US Privacy signals don't need to change their logic for a given discrete section of the string, as long as the implementation is aware of where the discrete section is.
New sections should follow the guidelines below. Guidelines like these help developers quickly adopt new sections and allow for parsing new sections without the need to reinvent new data types.
The possible data types are:
Data Type | Encoding | JS API output | Description |
Boolean |
1 bit | true|false | 0=true, 1=false |
Integer (fixed length of x) |
x bit | Number | A fixed amount of bit representing an integer. Usual lengths are 3, 6 or 12 bit. Example: int(6) “000101” represents the number 5 |
Integer (Fibonacci) |
Variable Length | Number | Integer encoded using Fibonacci encoding See “About Fibonacci Encoding” for more detail |
String (fixed length of x) (including country codes) |
x*6 bit | String | A fixed amount of bit representing a string. The character’s ASCII integer ID is subtracted by 65 and encoded into an int(6). Example: int(6) “101010” represents integer 47 + 65 = char “h” |
Datetime |
36 bit | Date | A datetime is encoded as a 36 bit integer representing the 1/10th seconds since January 01 1970 00:00:00 UTC. Example JavaScript representation: Math.round((new Date()).getTime()/100) |
Bitfield (fixed length of x) |
x bit | Array of Number | A fixed amount of bit. Usually each bit represents a boolean for an ID within a group where the first bit corresponds to true/false for ID 1, the second bit corresponds to true/false for ID 2 and so on. |
N-bitfield (Variable length Bitfield) |
variable | Array of Number | Consists of two datapoints: a fixed length Integer(16) that denotes the length and a bitfield with that specific length.
Please note: Although the API reads/writes to fields (length + bitfield), it will only output the IDs from the bitfield via JS APIs. |
Range (Int) |
variable | Array of Number | A range field always consists of the following fields:
|
Range (Fibonacci) |
variable | Array of Number | A range field always consists of the following fields:
|
OptimizedRange |
variable | Array of Number | Consists of two data types:
|
OptimizedIntRange |
variable | Array of Number | Consists of three data types:
|
ArrayOfRanges |
variable | [{'key':number, 'type':number, 'ids':Array of number}, {...}, ...] | Consists of a variable amount of fields:
Note: |
N-ArrayOfRanges(X,Y) |
variable | [{'key':number, 'type':number, 'ids':Array of number}, {...}, ...] | Consists of a variable amount of fields:
|
When defining a new section, regional policy writers should consider the above format to describe their section. Policy writers must ensure that each field within the section has a name that is unique for this section. When using multiple sub-sections within the section, field names with similar meanings (such as "type" or "version") shall be prefixed in order to be unique for the section (e.g. "coreVersion" and "publisherVersion").
Example Field name | Example Type | Example Description |
Version |
int(6) | Version of Specification XYZ |
LastUpdated |
datetime | Datetime of last update |
OptOutPurposes |
Bitfield(6) | Purposes the user opted out for, each bit representing the purpose ID |
... |
... | ... |
Note: It is recommended to use Field names in CamelCase and without any special characters or space. This allows the use of the same field names within other APIs (e.g. GPP JS API or GPP Mobile API)
Sub-Sections / Sections
If a section uses sub-sections to separate information or to be more flexible, it can use the delimiter “.” (dot) to separate the sub-sections from each other.
You can find all section specific details in the discrete section’s documentation.
Using the same cases as in the Header Examples above, the following examples provide a sample GPP string that represents the stated conditions.
GPP String Example 1 |
Conditions:
|
Encoded header:DBABM |
Full GPP String:DBABM~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA |
GPP String Example 2 |
Conditions:
|
Encoded header:DBACNY |
Full GPP String:DBACNY~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1YNN |
GPP String Example 3 |
Conditions:
|
Encoded header:DBABjw |
Full GPP String:DBABjw~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1YNN |
As part of the first version of GPP, signal integrity will be accomplished in concert with the Accountability Platform. The Global Privacy Working Group is committed to introducing signal integrity technology for GPP in future versions.
Callers needing to consume privacy signals with business entity level disclosures across multiple markets need the ability to do so with the assurance that business entities do not have duplicate or overlapping IDs. There are already existing vendor lists (see note with non-exhaustive list below) on which the same business entity may appear. Frameworks that are supported by the GPP must retrieve their IDs from the IAB Tech Lab Transparency Center. This will ensure the creation of concurrent non-overlapping vendor IDs.
Registration to participate in a specific framework is governed by the local jurisdiction Policy and T&Cs, who would also be responsible for enforcement and compliance.
Vendors should decide which framework signals they plan to participate in to determine which list registrations may be required. If approved, a GPP Identifier will be assigned.
Vendors looking to register for the TCF EU GVL or TCF Canada GVL should do so on this registration portal. Additional details on the Global Vendor List can be found in the TCF v2 Consent string and vendor list format specification.
Vendors looking to sign the MSPA may do so at the Transparency Center.
If you are a vendor with a GVL ID for a specific framework, you already have a GPP ID. However, you may still need to complete registration to participate in a specific framework.
When a creative is rendered, it may contain a number of pixels under <img>
tags. For example, <img src = "http://vendor-a.com/key1=val1&key2=val2">
which fires an HTTP GET request from the browser to Vendor A’s domain.
Since the pixel is in an <img>
tag without the ability to execute Javascript, the CMP API cannot be used to obtain the GPP String. All parties in the ad supply chain who transact using URLs must add a pair of macros in their URLs where the GPP String, and applicable GPP Section IDs (SID), are inserted. Any caller with access to the applicable GPP String must insert it within a URL containing the macros:
${GPP_STRING_XXXXX}
whereXXXXX
is the numeric GPP ID of the vendor receiving the string. - The applicable GPP Section ID must also be inserted, where the ${GPP_SID} macro is present.
Vendors not registered to participate in any framework supported by the Global Privacy Platform (e.g. MSPA, TCF CA, TCF EU) may pass ${GPP_STRING} without the GPP ID. Vendors who are registered to participate and have a GPP ID must include it in the macro. When vendors that are callers–who have the option to expand on the macros–are deciding how to proceed with vendor callees not participating in a GPP supported framework (e.g. MSPA, TCF CA, TCF EU), vendors should reference each framework's policy.
Example when ${GPP_STRING} rather than ${GPP_STRING_XXXXX}may be used:
The GPP String includes one of the US States sections or the US National section, but the string creator has indicated that the transaction is not covered by the MSPA. Vendors who do not participate in the MSPA may request the string, but may not have a GPP ID. In this case, ${GPP_STRING} may be used.
Example when ${GPP_STRING_XXXXX}is used:
Vendor A with ID 123 to receive a GPP String which includes the EU TCF v2 as applicable section, an image URL must include two key-value pairs with the URL parameters and macros gpp=${GPP_STRING_123}
and gpp_sid=${GPP_SID}
.
-
The resulting URL is:
http://vendor-a.com/key1-val1&key2=val2&gpp=${GPP_STRING_123}&gpp_sid=${GPP_SID}
-
If the GPP String is:
DBACNYA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1YNN
Then the caller replaces the macro in the URL with the actual GPP String so that the originally placed pixel containing the macro is modified as follows when making the call to the specified server.
http://vendor-a.com/key1=val1&key2=val2&gpp=DBACNYA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1YNN&gpp_sid=2
GPP Strings must always be propagated as is, and not modified. Additional URLs in the supply chain are addressed the same way with remaining vendors.
The available URL parameters and macros to relay information down the supply chain are listed in the following section.
Full GPP String passing
Services that are called using a URL from the user's browser, like cookie staplers, user id associators, and tracking pixels (the 'callee') are passed as macros within the URL and formatted as:
&url_parameter=${macro_name}
The supported URL parameters and the corresponding macros are defined below:
URL Parameter | Corresponding Macro | Representation in URL |
gpp | GPP_STRING_XXXXX (XXXXX is numeric GPP ID - the ID of the vendor on the GPP ID List who is expecting this URL call) |
&gpp=${GPP_STRING_123} |
gpp_sid | GPP_SID |
&gpp_sid=${GPP_SID} |
The service making the call must replace the macros with appropriate values described in the table below. For macro ${GPP_STRING_XXXXX}, the service making the call must also check that the macro name contains a valid GPP ID before replacing the macro.
The creator of the URL should ensure these parameters are added only once, and are passed to services which are expecting them and can handle them properly.
Macro | Possible Values | Purpose |
${GPP_STRING_XXXXX} | Url-safe base64-encoded GPP string. |
Encodes the GPP string, as obtained from the CMP JS API or OpenRTB |
${GPP_SID} | The section ID(s) in force for the current transaction. In most cases, this field should have a single section ID. In rare occasions where such a single section ID can not be determined, the field may contain up to 2 values, separated by a comma. |
As the GPP String may encode user preferences for multiple jurisdictions, this field indicates to the callee which section of the string is considered “in force” by the caller. This should match the value returned by the CMP API (see below). |