WEB CMP
Implement a Notice on a website using Javascript, as described below.

Latest changes

The last CMP web version is v28.7.12.
You will find amongst the latest changes:
You can find more details on Release notes page.
Open your HTML code source first.

1. Add the IAB stub in the <head> section of all your pages

The IAB STUB is a common block of code that rules some mandatories behaviors for CMP.
1
<!-- MANDATORY: BEGIN IAB STUB -->
2
<script type="text/javascript">
3
"use strict";!function(){var e=function(){var e,t="__tcfapiLocator",a=[],n=window;for(;n;){try{if(n.frames[t]){e=n;break}}catch(e){}if(n===window.top)break;n=n.parent}e||(!function e(){var a=n.document,r=!!n.frames[t];if(!r)if(a.body){var s=a.createElement("iframe");s.style.cssText="display:none",s.name=t,a.body.appendChild(s)}else setTimeout(e,5);return!r}(),n.__tcfapi=function(){for(var e,t=arguments.length,n=new Array(t),r=0;r<t;r++)n[r]=arguments[r];if(!n.length)return a;if("setGdprApplies"===n[0])n.length>3&&2===parseInt(n[1],10)&&"boolean"==typeof n[3]&&(e=n[3],"function"==typeof n[2]&&n[2]("set",!0));else if("ping"===n[0]){var s={gdprApplies:e,cmpLoaded:!1,cmpStatus:"stub"};"function"==typeof n[2]&&n[2](s)}else a.push(n)},n.addEventListener("message",(function(e){var t="string"==typeof e.data,a={};try{a=t?JSON.parse(e.data):e.data}catch(e){}var n=a.__tcfapiCall;n&&window.__tcfapi(n.command,n.version,(function(a,r){var s={__tcfapiReturn:{returnValue:a,success:r,callId:n.callId}};t&&(s=JSON.stringify(s)),e&&e.source&&e.source.postMessage&&e.source.postMessage(s,"*")}),n.parameter)}),!1))};"undefined"!=typeof module?module.exports=e:e()}();
4
</script>
5
<!-- MANDATORY: END IAB STUB -->
Copied!

2. Add the eventListener in the <head> section of all your pages

1
<!-- ADD EVENTILISTNER -->
2
<script type="text/javascript">
3
(adsbygoogle=window.adsbygoogle||[]).pauseAdRequests=1,window.dataLayer=window.dataLayer||[],__tcfapi("addEventListener",2,function(e,n){if(n&&e.gdprApplies&&("tcloaded"===e.eventStatus||"useractioncomplete"===e.eventStatus)){if((adsbygoogle=window.adsbygoogle||[]).pauseAdRequests=0,e.purpose.consents)
4
for(var s in window.dataLayer.push({AppConsent_IAB_PURPOSES:e.purpose.consents}),e.purpose.consents)e.purpose.consents[s]&&window.dataLayer.push({event:"appconsent_ctrl_"+s});var o,a;e.acExtraPurposes&&(o={},e.acExtraPurposes.forEach(function(e){o[e]=!0}),window.dataLayer.push({AppConsent_EXTRA_PURPOSES:o})),e.acExtraVendors&&(a={},e.acExtraVendors.forEach(function(e){a[e]=!0}),window.dataLayer.push({AppConsent_EXTRA_VENDORS:a})),e.purpose.consents&&e.vendor.consents&&("object"==typeof sfbxguardian&&e.purpose.consents[1]&&window.sfbxguardian.unblock(),"function"==typeof gtag&&(e.purpose.consents[1]&&e.vendor.consents[755]?gtag("consent","update",{analytics_storage:e.purpose.consents[7]||e.purpose.consents[9]?"granted":"denied",ad_storage:e.purpose.consents[3]?"granted":"denied "}):gtag("consent","update",{analytics_storage:"denied",ad_storage:"denied"})))}window.dataLayer.push({event:"appconsent_loaded"})});
5
</script>
6
<!-- END EVENTILISTNER -->
Copied!

3. Initialise and display the CMP

Put the following code at the end of the <body> tag:
1
<script src="https://cdn.appconsent.io/loader.js" defer async></script>
2
<script type="text/javascript">
3
__tcfapi('init', 2, console.log, {
4
appKey: 'YOUR_APP_KEY'
5
// targetCountries: ['FR', 'UK', 'US'],
6
// forceGDPRApplies: true,
7
})
8
</script>
9
10
<script type="text/javascript">
11
__tcfapi('show', 2, console.log, {
12
lazy: true,
13
})
14
</script>
Copied!
With the GDPR, you have the obligation to provide a way to the user to be able to udpate their choices at any time and easily. It is why you have to add the privacy center kit. This is why the privacyWidget is already install BUT you can choose the privacy center link if you want to add it on a "Cookies parameters'" link for example.
For more informations or to customize your Privacy center kit, please go to this page.
Be careful to not install the init js twice.

4. Using the appKey of your notice

4.1 Get the appKey

  • In the left menu, click on "Notices".
  • Find the line of the notice you want to implement.
  • It doesn’t appear automatically, click the row to make appKey appear.
  • A window appears with the matching appKey
  • Use the copy icon on the right to copy your AppKey

4.2 Insert appkey into your code

Paste the appkey in the piece of code you previously inserted in the <body>, at this level: " appKey: 'YOUR_APP_KEY' "

Results

Congratulations, at this point your cmp is implemented and over 700 marketing partners (IAB Vendors) are driven by your users' choices.
1
<html lang="en">
2
<head>
3
<meta charset="UTF-8">
4
<meta name="viewport" content="width=device-width, initial-scale=1.0">
5
<meta http-equiv="X-UA-Compatible" content="ie=edge">
6
<title>Your Website</title>
7
<!-- MANDATORY: BEGIN IAB STUB -->
8
<script type="text/javascript">
9
"use strict";!function(){var e=function(){var e,t="__tcfapiLocator",a=[],n=window;for(;n;){try{if(n.frames[t]){e=n;break}}catch(e){}if(n===window.top)break;n=n.parent}e||(!function e(){var a=n.document,r=!!n.frames[t];if(!r)if(a.body){var s=a.createElement("iframe");s.style.cssText="display:none",s.name=t,a.body.appendChild(s)}else setTimeout(e,5);return!r}(),n.__tcfapi=function(){for(var e,t=arguments.length,n=new Array(t),r=0;r<t;r++)n[r]=arguments[r];if(!n.length)return a;if("setGdprApplies"===n[0])n.length>3&&2===parseInt(n[1],10)&&"boolean"==typeof n[3]&&(e=n[3],"function"==typeof n[2]&&n[2]("set",!0));else if("ping"===n[0]){var s={gdprApplies:e,cmpLoaded:!1,cmpStatus:"stub"};"function"==typeof n[2]&&n[2](s)}else a.push(n)},n.addEventListener("message",(function(e){var t="string"==typeof e.data,a={};try{a=t?JSON.parse(e.data):e.data}catch(e){}var n=a.__tcfapiCall;n&&window.__tcfapi(n.command,n.version,(function(a,r){var s={__tcfapiReturn:{returnValue:a,success:r,callId:n.callId}};t&&(s=JSON.stringify(s)),e&&e.source&&e.source.postMessage&&e.source.postMessage(s,"*")}),n.parameter)}),!1))};"undefined"!=typeof module?module.exports=e:e()}();
10
</script>
11
<!-- MANDATORY: END IAB STUB -->
12
13
<!-- ADD EVENTILISTNER -->
14
<script type="text/javascript">
15
(adsbygoogle=window.adsbygoogle||[]).pauseAdRequests=1,window.dataLayer=window.dataLayer||[],__tcfapi("addEventListener",2,function(e,n){if(n&&e.gdprApplies&&("tcloaded"===e.eventStatus||"useractioncomplete"===e.eventStatus)){if((adsbygoogle=window.adsbygoogle||[]).pauseAdRequests=0,e.purpose.consents)
16
for(var s in window.dataLayer.push({AppConsent_IAB_PURPOSES:e.purpose.consents}),e.purpose.consents)e.purpose.consents[s]&&window.dataLayer.push({event:"appconsent_ctrl_"+s});var o,a;e.acExtraPurposes&&(o={},e.acExtraPurposes.forEach(function(e){o[e]=!0}),window.dataLayer.push({AppConsent_EXTRA_PURPOSES:o})),e.acExtraVendors&&(a={},e.acExtraVendors.forEach(function(e){a[e]=!0}),window.dataLayer.push({AppConsent_EXTRA_VENDORS:a})),e.purpose.consents&&e.vendor.consents&&("object"==typeof sfbxguardian&&e.purpose.consents[1]&&window.sfbxguardian.unblock(),"function"==typeof gtag&&(e.purpose.consents[1]&&e.vendor.consents[755]?gtag("consent","update",{analytics_storage:e.purpose.consents[7]||e.purpose.consents[9]?"granted":"denied",ad_storage:e.purpose.consents[3]?"granted":"denied "}):gtag("consent","update",{analytics_storage:"denied",ad_storage:"denied"})))}window.dataLayer.push({event:"appconsent_loaded"})});
17
</script>
18
<!-- END EVENTILISTNER -->
19
20
<!-- Global site tag (gtag.js) - Google Analytics -->
21
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXX"></script>
22
<script>
23
window.dataLayer = window.dataLayer || [];
24
function gtag(){dataLayer.push(arguments);}
25
gtag('consent', 'default', {
26
'ad_storage': 'denied',
27
'analytics_storage': 'denied'
28
});
29
gtag('js', new Date()); gtag('config', 'G-XXXXXXXXXX');
30
</script>
31
32
</head>
33
<body>
34
35
<script src="https://cdn.appconsent.io/loader.js" defer async></script>
36
<script type="text/javascript">
37
__tcfapi('init', 2, console.log, {
38
appKey: 'YOUR_APP_KEY'
39
// targetCountries: ['FR', 'UK', 'US'],
40
// forceGDPRApplies: true,
41
})
42
</script>
43
44
<script type="text/javascript">
45
__tcfapi('show', 2, console.log, {
46
lazy: true,
47
})
48
</script>
49
50
51
</body>
52
</html>
Copied!

Add on

Here is a typical GA tag
1
<!-- Global site tag (gtag.js) - Google Analytics -->
2
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-XXXXXXXXX-1"></script>
3
<script>
4
window.dataLayer = window.dataLayer || [];
5
function gtag(){dataLayer.push(arguments);}
6
7
gtag('js', new Date()); gtag('config', 'G-XXXXXXXXXX');
8
</script>
Copied!
Now we add a special command that will initialize gtag() with denied settings in order to don't drop cookies before user 's choice. The CMP will drive the tag according to the right consent given.
1
2
gtag('consent', 'default', {
3
'ad_storage': 'denied',
4
'analytics_storage': 'denied'
5
});
Copied!
The original code becomes this
1
<!-- Global site tag (gtag.js) - Google Analytics -->
2
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-XXXXXXXXX-1"></script>
3
<script>
4
window.dataLayer = window.dataLayer || [];
5
function gtag(){dataLayer.push(arguments);}
6
gtag('consent', 'default', {
7
'ad_storage': 'denied',
8
'analytics_storage': 'denied'
9
});
10
gtag('js', new Date()); gtag('config', 'G-XXXXXXXXXX');
11
</script>
Copied!

That's it - The CMP will control Google Analytics according to the choice of the user

Congratulations ( again ) , at this point your cmp is implemented and over 700 marketing partners (IAB Vendors) and Google Analytics Family are driven by your users' choices.

How to control others tags ?

Your CMP has a new feature called "Guardian" which allows you to block tags very easily. Please see this section to learn more.

Go Further

Now that you have implemented your CMP you can put some extra commands or settings by reading the following instructions.

Passing commands in URL

You can pass commands to the CMP through the querystring. Querystring commands are evaluated on init.
?ac_cmd=show
The above link would show the CMP on init.
You can also pass parameters to the command with the same mechanism. Parameters are passed as is from the querystring. Consider the following example:
?ac_cmd=show&jumpAt=banner

Commands / CMP Calls

CMP can be controlled through iAB's __tcfApi global function, as documented.
Custom calls are providen to operate the CMP, like displaying it, activating programmatic consent and so on. All Custom calls are asynchronous functions receiving an error-first callback and optional arguments, as follow:

init

Init the CMP with AppConsent credentials and additionnal configurations.
argument name
type
optional
value
command
string
'init'
version
number
2
callback
function
function(error: Error, state: State)
parameter
Object
Configuration
Callback returns the CMP's state, retrieved from either LocalStorage or server. State contains Consent and Vendorlist. This command performs at most one server call.

Basic Example

1
__tcfapi('init', 2, console.log, {
2
appKey: 'YOUR_APPKEY',
3
})
Copied!

Basic Example with i18n

1
__tcfapi('init', 2, console.log, {
2
appKey: '123',
3
i18n: {
4
buttons_acceptAll: { values: { en: 'ACCEPT ALL' } },
5
},
6
})
Copied!

Advanced Example with passing ExternalID (UUID key )

1
__tcfapi('init', 2, console.log, {
2
appKey: 'appKey',
3
uuid: 'YOUR_ID_ABCD12345678',
4
debug: true,
5
storage: true,
6
i18n: {
7
banner_title: { values: { fr: 'Démo i18n' } },
8
buttons_acceptAll: { values: { fr: 'Démo i18n Accept' } },
9
},
10
})
Copied!

Configuration object

1
/**
2
* Configuration holds settings for the current CMP instance
3
* Can be overriden by passing it to the init custom command
4
*/
5
export var configuration = {
6
/**
7
* string - 🛂 MANDATORY credentials for the AppConsent API
8
*/
9
appKey: null,
10
11
/**
12
* true - activate verbose logging in the browser's console
13
*/
14
debug: false,
15
16
/**
17
* true - CMP will be displayed to all visitors from any country in the world
18
*/
19
forceGDPRApplies: false,
20
/**
21
* Non-empty array of strings (country codes) is accepted or null
22
* CMP will be displayed to the provided list of country codes
23
* Example: ['FR,'IT','RU','US']
24
*/
25
targetCountries: null,
26
27
/**
28
* true - show keys instead of traductions for i18n keys
29
*/
30
debugI18n: false,
31
32
/**
33
* true - Force static fallback, bypassing the AppConsent API.
34
*/
35
forceStatic: false,
36
37
/**
38
* true - Force iAB global mode operation. Consent is stored on .consensu.org
39
*/
40
global: false,
41
42
/**
43
* Object - Overrides translation keys
44
*/
45
i18n: {},
46
47
/**
48
* string - URL to the static fallback of the AppConsent Vendorlist.
49
*/
50
"static": null,
51
52
/**
53
* true - Use the localstorage (default)
54
* false - localstorage is ignored
55
* Function - retrieve a Storage object from this function
56
* TODO see the section: "No section here"
57
*/
58
storage: true,
59
60
/**
61
* string - domain of the AppConsent API
62
*/
63
url: '',
64
65
/**
66
* string - overrides AppConsent's uuid generation
67
*/
68
uuid: null
69
};
Copied!

Static mode

A static example file can be found here: collector-fr.json

show

Displays the CMP for collecting user consents.
argument name
type
optional
value
command
string
'show'
version
number
2
callback
function
function(error: Error)
parameter
Object
ShowOption
1
ShowOption = {
2
/**
3
* true - If a consent if present, won't bother the user
4
* false (default) - Show the banner no matter what
5
*/
6
lazy: Boolean,
7
/**
8
* null, 'banner'
9
* 'privacy'
10
*/
11
jumpAt: string
12
}
Copied!
Example:
1
__tcfapi('show', 2, console.log, {
2
lazy: false,
3
})
Copied!
Example:
1
__tcfapi('show', 2, console.log, {
2
jumpAt: 'privacy',
3
})
Copied!

accept

Registers a full consent on the CMP, as the user would have clicked on the "accept everyhting" button. The default behavior is to prevent overwriting any existing consent. You can force overwriting by specifying a special force parameter.
Note that no matter the outcome, this call will hide the UI.
argument name
type
optional
value
command
string
'accept'
version
number
2
callback
function
function(error: Error)
parameter
Object
AcceptOption
1
AcceptOption = {
2
/**
3
* true - Overwrite any consent by an "accept all" one
4
* false (default) - "accept all" unless a consent is already defined
5
*/
6
force: Boolean,
7
}
Copied!
Example:
1
__tcfapi('accept', 2, console.log)
Copied!

deny

argument name
type
optional
value
command
string
'deny'
version
number
2
callback
function
function(error: Error)
parameter
Example:
1
__tcfapi('deny', 2, console.log)
Copied!

fakedeny

Forge a deny consentstring and return it to all vendors, without saving it as a user legitimate consent. This is useful to prevent unhonorable vendors from assuming lack of consent is one. This WONT hide the UI.
argument name
type
optional
value
command
string
'fakedeny'
version
number
2
callback
function
function(error: Error)
parameter
Example:
1
__tcfapi('fakedeny', 2, console.log)
Copied!

More

How heavy is this CMP ?

We're leveraging chunking to alleviate bandwith. Code for the UI is only downloaded when user interaction is needed. Beside, we do have a nice size report.

Tag managers compatibility

We've decided to not support directly tag managers, as implementation and usages varies. We strongly encourage you to use the standard TCF v2 API to achieve consent resolution for your tags. But it's very easy to interract with them.
For example, a GTM implementation could look like this, provided we only strive for a full consent:
1
__tcfapi('getTCData', 2, (tcData, ok) => {
2
if(ok) {
3
for (var c in tcData.purpose.consents) {
4
if (tcData.purpose.consents[c]) {
5
// Push events to GTM
6
window.dataLayer.push({ event: 'purpose_' + c })
7
}
8
}
9
}
10
});
Copied!
Or for Tag Commander:
1
__tcfapi('getTCData', 2, (tcData, ok) => {
2
if(ok) {
3
var tcVars = {}
4
for (var c in tcData.purpose.consents) {
5
if (tcData.purpose.consents[c]) {
6
// Build a TagCommander events object
7
tcVars['purpose_' + c] = '1'
8
}
9
}
10
// Push events to Tag Commander
11
window.tcEvents(null, 'sfbx_consent_action', tcVars)
12
}
13
});
Copied!
Very simple exemple :
1
__tcfapi('getTCData', 2, (tcData, success) => {
2
if(success) {
3
console.log(tcData.tcString)
4
} else {
5
// do something else
6
}
7
});
Copied!
Will output your tcString V2 in your console :
1
CO3czkfO3czkfACAGAFRArCgAL_AAD_AAAqIGBtX_T5eb2vje3Zdt9tkaYwf55y3o-wjhgaIse8NwIeH7BoGL2MwvBX4JiQCGBAEEiKBAQdlHGBcCQAAgIgBiTKMYk2MCzNKJLJAilMbc0NYCC1mnsHTmZCY7068O__zv3eBghBJgqXgEiQthASTZpRCmACEcQFSDgEoIQgIFLDQAEBOwKAj1AAAAQGAAEAAAAIIICAQACAABIRAAAAICAUAEQCAAEAI0BCAAiQIBYASJAEAAqBoSAEUQQgCEHBgFHKIEBQAAAAA.YAAAAAAAAAAA
Copied!
More information in the official IAB Documentation here.

Edition of consents without displaying the CMP

When you website embeds external integrations (Youtube, Twitch, Twitter, etc.), you may need to modify consents of a user (with their agreement) to give access to this content without redisplaying the CMP. To do this, you can use the updateStatus function. This is how to use it:
1
__tcfapi('updateStatus', 2, () => {}, [{t: <type>, id: <id>, status: <bool-value> }])
Copied!
The list of possible types <type> is the following one:
  • 1 - Purpose
  • 2 - Extra purpose
  • 3 - Special feature
  • 4 - IAB vendor
  • 5 - Extra vendor
The ID <id> is the one of the object you want to enable/disable. Its nature depends on the object represented by <type>. You can see the list of available types and IDs for your notice through getTCData call (see usage example here).
The value <bool-value> enables (true) or disables (false) for the tuple (<type>, <id>).
An error will be returned if the consent of the user does not exist yet, of if any of the input combinations (<type>, <id>) does not exist in the array in argument.
To find the latest updates of the CMP, see the "Release Notes" section.
Last modified 1mo ago