Skip to content
forked from appnexus/cmp

System1's implementation of IAB's Transparency and Consent 2.0 Consent Management Platform. A TCF 2.0 compliant CMP that passes all IAB compliance checks and has been validated to participate as a CMP for private use as CMP 38.

License

Notifications You must be signed in to change notification settings

Openmail/system1-cmp

 
 

Repository files navigation

system1-cmp

System1's implementation of IAB's Transparency and Consent 2.0 Consent Management Platform. A TCF 2.0 compliant CMP that passes all IAB compliance checks and has been validated to participate as a CMP for private use as CMP 38.

This CMP passes technical and policy compliance checks, but that does not necessarily guarantee legal compliance. Each organisation must make their own assessment of whether they are compliant with the law.

Feel free to fork this CMP and submit to IAB for private use.

Reference Page and Demo

SDK / Package Details

  • tcf-2.0-loader.js is < 1kb. It loads the CMP sdk and dynamically checks compatibility and loads the polyfill if necessary.
  • tcf-2.0-cmp.js is < 50kb. It contains the TCF 2.0 framework (core/api), UI layer for interacting with the CMP, and custom store for persisting choices.
  • polyfills.js is < 15kb. It contains polyfills required for the CMP to function in IE11.

Installation / Use

See a working example in codepen.

<script src="https://s.flocdn.com/cmp/2.1.1/tcf-2.0-loader.js"></script>
<script>
	__tcfapi('onConsentAllChanged', 2, function (store) {
		const hasConsented = document.cookie.indexOf('gdpr_opt_in=1') >= 0;
		if (hasConsented) {
			console.log('cmp:onConsentAllChanged: all consent achieved', store.tcData.tcString);
		} else {
			console.log('cmp:onConsentAllChanged: only some consent achieved', store.tcData.tcString);
		}
	});

	__tcfapi(
		'init',
		2,
		function (store, error) {
			console.log('initialization complete', store, error);
		},
		{
			business: 'business:unit',
			gdprApplies: true, // true for EU false for CA
			ccpaApplies: false, // true for CA false for EU
			canLog: true,
			canDebug: true,
			isServiceSpecific: true, // on service-specific use supported right now
			baseUrl: 'https://s.flocdn.com/cmp/2.1.1/config/2.0', // base url
			scriptSrc: 'https://s.flocdn.com/cmp/2.1.1/tcf-2.0-cmp.js', // cmp SDK
			publisherCountryCode: 'US',
			// language: '', // empty string or unset to default to browser language
			shouldUseStacks: true,
			isSlimMode: true,
			// narrowedVendors: [1, 2, 3, 4, 5, 6],
			theme: {
				boxShadow: 'none',
				featuresColor: '#d0d3d7',
				maxHeightModal: '40vh',
				primaryColor: '#0099ff',
				secondaryColor: '#869cc0',
				shouldAutoResizeModal: true, // resizes modal on stacks screen to push stacks below fold
				textLinkColor: '#0099ff',
				isFullWidth: false,
			},
		}
	);
</script>

API

Read more about __tcfapi built-in API

  • ping
  • addEventListener
  • removeEventListener
  • getTCData
  • getInAppTCData
  • getVendorList

Customized API

init

Calling __tcfapi('init', 2, (store) => {}) will trigger the seed-file or loader to async load the larger CMP UI application. Once loaded, the cmp library calls init function to load additional dependencies and render the application.

init callback should be called regardless of internal errors as errors need to be handled gracefully internally to not disrupt the parent website.

/**
 * @param 'init' // required string command
 * @param apiVersion // required number, 2, version of api in use,
 * @param callback // required function, called when init completes, called with `store`
 * @param configurationOptions // optional object, used customize the CMP
 * @return void
 */
__tcfapi('init', apiVersion, callback, configurationOptions);

onConsentAllChanged

Calling __tcfapi('onConsentAllChanged', 2, (store) => {}) triggers the callback whenever the gdpr_opt_in cookie changes. We track an all-or-nothing hasConsentedAll mode so you can more easily toggle an anonymous mode on your website.

/**
 * @param 'onConsentAllChanged' // required string command
 * @param apiVersion // required number, 2, version of api in use,
 * @param callback // required function, called when gdpr_opt_in value changes from undefined (no consent yet), 1 (contented all), 0 (declined anything)
 * @return cachedListener // cache the callback if you need to remove this listener later
 */
const cachedListener = __tcfapi('onConsentAllChanged', apiVersion, callback);

offConsentAllChanged

Calling __tcfapi('offConsentAllChanged', 2, cachedListener) removes the listener setup in __tcfapi('onConsentAllChanged').

/**
 * @param 'onConsentAllChanged' // required string command
 * @param apiVersion // required number, 2, version of api in use,
 * @param cachedListener // optional function, include to remove a specific listener that was setup with `onConsentAllChanged`
 * @return void
 */
const cachedListener = __tcfapi('onConsentAllChanged', apiVersion, callback);
__tcfapi('offConsentAllChanged', apiVersion, cachedListener); // remove a specific event listener
__tcfapi('offConsentAllChanged', apiVersion); // remove all `onConsentAllChanged` event listeners

showConsentTool

Calling __tcfapi('showConsentTool', 2, () => {}) will display the CMP UI.

/**
 * @param 'showConsentTool' // required string command
 * @param apiVersion // required number 2
 * @param callback // required function, called when showConsentTool complete, called with `store`
 */
__tcfapi('showConsentTool', 2, (store) => {});

changeLanguage

Calling __tcfapi('changeLanguage', 2, () => {}, language) will use cached version or load language dependencies and re-render the application in the desired language

/**
 * @param 'changeLanguage' // required string command
 * @param apiVersion // required number 2
 * @param callback // required function, called when changeLanguage completes, called with `store` and result
 * @param language // required string, 2-letter language-code en,bg,ca,cs,da,de... etc. See constants.js file for supported languages
 */
__tcfapi('changeLanguage', 2, (store) => {}, 'pt'); // changes to Portuguese

changeConfig

Calling __tcfapi('changeConfig', 2, () => {}, {isSlimMode: true, theme: {isInlineMode: false}}) will update config values and rerender CMP UI

/**
 * @param 'changeConfig' // required string command
 * @param apiVersion // required number 2
 * @param callback // required function, called when changeLanguage completes, called with `store` and result
 * @param config // required object, merges with existing config object providing during `init()`
 */
__tcfapi('changeConfig', 2, (store) => {}, { theme: { isInlineMode: false } }); // changes config to use inline-mode

Configuration / Config

Set configuration for your CMP during the init phase.

__tcfapi('init', 2, () => {}, {
	theme: {
		maxHeightModal: '50vh',
		shouldAutoResizeModal: true,
		primaryColor: '#0099ff',
	},
	canLog: true, // pixel logging for monitoring and alerting
	canDebug: false, // console.logs for dev debugging
	narrowedVendors: [1, 2, 3, 4, 5], // only show a select vendors
	cookieDomain: '', // which domain to set the euconsent and gdpr_opt_in cookie on
});
Config Property Type Default Detail
canLog optional boolean false true enables DPL logging for health monitoring. Add #s1&debug=true to URL for easy DPL debugging
canDebug optional boolean false true enables internal console logging for debugging
baseUrl optional string ./config/2.0 relative or absolute url to load the global vendor list. Combines with versionedFilename to load vendorlist.
versionedFilename optional string vendor-list.json file name of the global vendor list.
narrowedVendors optional array [] Only show select vendors. Example [1,4,5,19]
language optional string null 2-character language code to initialize CMP with. If no language matches, CMP boots with en Ex 'en', 'ja', 'it'
languageFilename optional string purposes/purposes-[LANG].json file name template for gvl localized purpose json files
translationFilename optional string translations/translations-[LANG].json file name template for custom localized json files for UI layer
cookieDomain optional string null manage consent across subdomains. Example .mysite.com
gdprApplies optional boolean false Please pass true if being used on EU traffic where active consent is required
ccpaApplies optional boolean false Please pass true if being used on USA:CA traffic where "Do Not Sell" initiates CMP passively
experimentId optional string control use to indicate changes / upgrades in your CMP implementation for reporting / monitoring purposes.
business optional string dev used to correlate CMP events for monitoring across a businessline.
theme optional object details below Override styling choices using the following properties.
publisherCountryCode optional string US String representing country code of parent website business
isServiceSpecific optional boolean true true uses publisher consent, false uses global consent
shouldAutoShowModal optional boolean true true will automatically display UI modal after init, false will not
shouldAlwaysShowSaveButton optional boolean false true will always show the save button on the UI. False will only display the save button when a change is made
shouldUseStacks optional boolean true true uses stacks on Layer1, TODO stacks need purposes/custom-features toggle to be compliant
isSlimMode optional boolean false If true, initial banner is low profile, full width banner v2.1.4+
shouldShowCloseX optional boolean false If true, a × icon will appear in the upper right on layers to accept-all and close v2.1.4+
insertionNode optional string <body> UI will be appended to this element using querySelector. Default behavior appends to body v2.2.0+

theme

Themeing is a bit limited right now. Pass in a config.theme object during initialization. Use the following to override styling choices:

Theme Property Type Default Detail
maxHeightModal optional string 45vh CSS style for max height of the CMP UI. Example: 45vh, 50%, 350px
maxWidthModal optional string 1024px CSS style for max width of the CMP UI. Example: 1024px, calc(90% - 100px)
maxHeightInline optional string 200px CSS style to force max-height of CMP UI while in isBannerInline mode only.
shouldAutoResizeModal optional boolean true Auto detects Layer1 height to minimize UI. UI resizes to maxHeightModal upon interaction
primaryColor optional string null Example: #0099ff
textLinkColor optional string null Example: #0099ff
secondaryColor optional string null Example: #869cc0
featuresColor optional string null Example: #d0d3d7
backgroundColor optional string null Example: #d0d3d7 Sets the background color of the banners. v2.1.4+
isFullWidth optional boolean false Removes rounded corners and makes banners full width - matching style layout slimMode v2.1.4+
isBannerInline optional boolean false Renders CMP inline instead of overlaying layout. Subsequent CMP views open in modal v2.2.0+
shouldShowDropShadow optional boolean true When set to true, displays the drop shadoq on banners v2.1.4+

Initialize With Euconsent String from URL Param

We can leverage the spec provided for URL-based services to process the TC String when it can't execute JavaScript to pass along consent when domains are owned by the same entity.

Using a URLParam gdpr_consent you can pass consent to another domain that is using this CMP.

?gdpr_consent=${TC_STRING}

The CMP will use ?gdpr_consent URLParam to automatically persist consent and trigger consent change-events if there is not already an existing consent signal stored in the EUConsent cookie.

Background and Resources

The UI layer is inspired by this IAB TCF CMP UI Webinar presentation.

This CMP leverages the core, cmpapi, and stub modules from IAB's official TCF 2.0 JS SDK iabtcf-es.

The component library was forked and edited from the original TCF 1.0 CMP by AppNexus.

Following Google's Additional Consent Mode and Interoperability guidance for vendors this CMP provides cached versions of the vendor-list-test-google and standard vendor-list vendor list.

TODO

  • Write Unit Tests and Integration Tests
  • Improve Theming
  • Implement global-scope and group-scope
  • Updated hosted iframe for TCF 2.0
  • Delete unused TCF 1.1 and reorganize

Support Matrix

  • ✔ Level 1: Tested and fully supported, all functional and visual bugs should be fixed.
  • ✢ Level 2: Untested or Partially tested, functional bugs reported are fixed, visual appearance may differ.
  • ✳ Level 3: A separate solution or codebase exists to support this browser
  • ✘ Not Supported: Untested tested, functional bugs expected and not fixed.
Browser ✔ Level 1 ✢ Level 2 ✳ Level 3 ✘ Not Supported
Chrome ✔ Latest ✢ Latest - 2
Safari ✔ Latest ✢ Latest - 2
Edge ✔ Latest ✢ Latest - 2 (Win10)
IE ✔ IE11 (Win8.1) ✢ IE11(Win7 / Metro) ✘ IE10, IE9,...
Firefox ✔ Latest ✢ Latest - 2
iOS Safari ✔ Latest ✢ Latest - 2
Android Chrome ✔ Latest ✢ Latest - 2
Android Browser ✘ Default Browser
Opera

Contributing

For now the TCF 1.1 and TCF 2.0 CMPs both live in this repository. We will deprecate and remove TCF 1.1 and update all tests against the new 2.0 package. To contribute, make updates to the files in src/s1.

yarn
yarn dev
# browse to http://localhost:8080/tcf-2.0.html

Update Vendor List

IAB updates the vendor list every Friday. Use the included to script to automatically upgrade all vendor-lists. Commit, merge, publish the changes to take effect.

yarn upgrade-vendor-list

About

System1's implementation of IAB's Transparency and Consent 2.0 Consent Management Platform. A TCF 2.0 compliant CMP that passes all IAB compliance checks and has been validated to participate as a CMP for private use as CMP 38.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 87.1%
  • Less 7.6%
  • HTML 5.3%