Skip to main content

Migration of the CMP implementation

Since version 30.0.0 of the CMP, the implementation in your website has been simplified. In the page, we will see how to migrate step by step from old implementation to the new one.


IAB STUB​

From now on, the IAB STUB is automatically added to your website when the loader is initialized. It is therefore no longer necessary to have the following script in the <head> section of all the pages of your website:

To delete
<!-- MANDATORY: BEGIN IAB STUB -->
<script type="text/javascript">
"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()}();
</script>
<!-- MANDATORY: END IAB STUB -->

Event listener​

The event listener has been integrated directly into the notice, so it is no longer necessary to add it on all the pages of your website. You can therefore remove the following script from your website.

To delete
<!-- ADD EVENTLISTENER -->
<script type="text/javascript">
(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)
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"})});
</script>
<!-- END EVENTLISTENER -->

The init and show commands​

From now on, the init and show commands are automatically executed at the initialization of the notice and this implies changes in the implementation of the notice.

The init command​

Previously, it was necessary to implement the following script in the <body> section of HTML pages.

Old implementation
<script type="text/javascript">
__tcfapi('init', 2, console.log, {
appKey: 'YOUR_APP_KEY'
// targetCountries: ['FR', 'UK', 'US'],
// forceGDPRApplies: true,
})
</script>

Now that command was integrated of the notice, only the configuration needs to be defined. The configuration must be placed in variable named configSFBXAppConsent.

caution

This variable must be placed in the <head> section of your pages before the loader call

<script type="text/javascript">
const configSFBXAppConsent = {
appKey: 'YOUR_APP_KEY'
// targetCountries: ['FR', 'UK', 'US'],
// forceGDPRApplies: true,
}
</script>

Callback of the init command​

If you have defined a callback in the init command, you must now add it to the configSFBXAppConsent configuration variable in the callbacks parameter.

As a reminder, the callback will be executed at the end of the initialization of the notice. And takes as input parameters error and state.

info

In the documentation for the old implementation, we suggested putting console.log as a callback to the command. If you are in this case, it is no longer necessary to set it as callback.

Example of init callback configuration :

<script type="text/javascript">
const configSFBXAppConsent = {
appKey: 'YOUR_APP_KEY',
callbacks: {
init: ( error, state ) => {},
}
}
</script>

The show command​

Same as the init command, the show command no longer needs to be implemented like this :

old implementation
<script type="text/javascript">
__tcfapi('show', 2, console.log, {
lazy: true,
})
</script>

From now on, the configuration of this command must be added to the configSFBXAppConsent variable.

<script type="text/javascript">
const configSFBXAppConsent = {
appKey: 'YOUR_APP_KEY',
lazy: true,
}
</script>

Callback of show command​

If you defined a callback in the show command, you must now add it to the configSFBXAppConsent configuration variable in callbacks parameter.

As a reminder, this callback will be executed at the end of the command execution. And takes as input parameter error.

info

In the example code of the old implementation, we proposed in the documentation to put console.log in the callback of the command If you are in this case, it is no longer necessary to put it in callback.

Example of callback configuration :

<script type="text/javascript">
const configSFBXAppConsent = {
appKey: 'YOUR_APP_KEY',
callbacks: {
show: ( error ) => {}
}
}
</script>

Change in the configuration of the cmp​

Option url​

The url option has now the following default value : https://collector.appconsent.io. It is not necessary to have this option in your cmp configuration, if you use this url.

old implementation
<script type="text/javascript">
__tcfapi('init', 2, console.log, {
appKey: 'YOUR_APP_KEY',
url: 'https://collector.appconsent.io',
})
</script>

New implementation

<script type="text/javascript">
const configSFBXAppConsent = {
appKey: 'YOUR_APP_KEY'
}
</script>

Option lazy​

The lazy option is now enabled by default, if you had enabled the lazy option, it is no longer required to have it in the configuration.

old implementation
<script type="text/javascript">
__tcfapi('show', 2, console.log, {
lazy: true,
})
</script>

New implementation

<script type="text/javascript">
const configSFBXAppConsent = {
appKey: 'YOUR_APP_KEY'
}
</script>

Guardian​

If you haven't implemented guardian, you can skip this chapter.

The guardian configuration has been changed. Previously, it was necessary to add a <script> tag in which you defined the urls you wanted to blacklist or whitelist.

Old implementation
<script>
window.SFBX_GUARDIAN_BLACKLIST = [
/facebook/, /youtube/,
]
// Or a whitelist
window.SFBX_GUARDIAN_WHITELIST = [
/appconsent/,
]
</script>

Now this configuration must be put in the configuration variable configSFBXAppConsent with the parameter dynamicallyLoadedScripts with two subparts blacklist and whitelist.

<script type="text/javascript">
const configSFBXAppConsent = {
appKey: 'YOUR_APP_KEY',
dynamicallyLoadedScripts: {
blacklist: [
/facebook/, /youtube/,
],
whitelist: [
/appconsent/,
]
},
}
</script>

The Guardian script has been changed to accommodate this new way of configuring Guardian. So you have to replace the old <script> tag containing the Guardian code with this one:

To change
<script>
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t=t||self).sfbxguardian={})}(this,function(t){"use strict";function o(e,t){return e&&(!t||t!==c)&&(!s.blacklist||s.blacklist.some(function(t){return t.test(e)}))&&(!s.whitelist||s.whitelist.every(function(t){return!t.test(e)}))}function l(t){var e=t.getAttribute("src");return s.blacklist&&s.blacklist.every(function(t){return!t.test(e)})||s.whitelist&&s.whitelist.some(function(t){return t.test(e)})}if(typeof configSFBXAppConsent === 'undefined'){console.error('SFBX Guardian has not been executed! The configuration (configSFBXAppConsent) must be placed before calling the script '); return}if(!configSFBXAppConsent.dynamicallyLoadedScripts||(!configSFBXAppConsent.dynamicallyLoadedScripts.blacklist&&!configSFBXAppConsent.dynamicallyLoadedScripts.whitelist)){console.warn('SFBX Guardian: No whitelist or blacklist has been defined'); return;}var c="javascript/blocked",s={blacklist:configSFBXAppConsent.dynamicallyLoadedScripts.blacklist,whitelist:configSFBXAppConsent.dynamicallyLoadedScripts.whitelist},u={blacklisted:[]},f=new MutationObserver(function(t){for(var e=0;e<t.length;e++)for(var i=t[e].addedNodes,r=function(t){var r=i[t];if(1===r.nodeType&&"SCRIPT"===r.tagName){var e=r.src,n=r.type;if(o(e,n)){u.blacklisted.push([r,r.type]),r.type=c;r.addEventListener("beforescriptexecute",function t(e){r.getAttribute("type")===c&&e.preventDefault(),r.removeEventListener("beforescriptexecute",t)}),r.parentElement&&r.parentElement.removeChild(r)}}},n=0;n<i.length;n++)r(n)});f.observe(document.documentElement,{childList:!0,subtree:!0});var i=document.createElement,a={src:Object.getOwnPropertyDescriptor(HTMLScriptElement.prototype,"src"),type:Object.getOwnPropertyDescriptor(HTMLScriptElement.prototype,"type")};function p(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(t)))return;var r=[],n=!0,i=!1,o=void 0;try{for(var c,a=t[Symbol.iterator]();!(n=(c=a.next()).done)&&(r.push(c.value),!e||r.length!==e);n=!0);}catch(t){i=!0,o=t}finally{try{n||null==a.return||a.return()}finally{if(i)throw o}}return r}(t,e)||r(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function d(t){return function(t){if(Array.isArray(t))return n(t)}(t)||function(t){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(t))return Array.from(t)}(t)||r(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function r(t,e){if(t){if("string"==typeof t)return n(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);return"Object"===r&&t.constructor&&(r=t.constructor.name),"Map"===r||"Set"===r?Array.from(t):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?n(t,e):void 0}}function n(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r<e;r++)n[r]=t[r];return n}document.createElement=function(){for(var t=arguments.length,e=new Array(t),r=0;r<t;r++)e[r]=arguments[r];if("script"!==e[0].toLowerCase())return i.bind(document).apply(void 0,e);var n=i.bind(document).apply(void 0,e);try{Object.defineProperties(n,{src:{get:function(){return a.src.get.call(this)},set:function(t){o(t,n.type)&&a.type.set.call(this,c),a.src.set.call(this,t)}},type:{set:function(t){var e=o(n.src,n.type)?c:t;a.type.set.call(this,e)}}}),n.setAttribute=function(t,e){"type"===t||"src"===t?n[t]=e:HTMLScriptElement.prototype.setAttribute.call(n,t,e)}}catch(t){console.warn("sfbxguardian: unable to prevent script execution for script src ",n.src,".\n",'A likely cause would be because you are using a third-party browser extension that monkey patches the "document.createElement" function.')}return n};var y=new RegExp("[|\{}()[\\]^$+*?.]","g");t.unblock=function(){for(var t=arguments.length,r=new Array(t),e=0;e<t;e++)r[e]=arguments[e];r.length<1?(s.blacklist=[],s.whitelist=[]):(s.blacklist&&(s.blacklist=s.blacklist.filter(function(e){return r.every(function(t){return"string"==typeof t?!e.test(t):t instanceof RegExp?e.toString()!==t.toString():void 0})})),s.whitelist&&(s.whitelist=[].concat(d(s.whitelist),d(r.map(function(e){if("string"==typeof e){var r=".*"+e.replace(y,"\\$&")+".*";if(s.whitelist.every(function(t){return t.toString()!==r.toString()}))return new RegExp(r)}else if(e instanceof RegExp&&s.whitelist.every(function(t){return t.toString()!==e.toString()}))return e;return null}).filter(Boolean)))));for(var n=document.querySelectorAll('script[type="'.concat(c,'"]')),i=0;i<n.length;i++){var o=n[i];l(o)&&(u.blacklisted.push([o,"application/javascript"]),o.parentElement.removeChild(o))}var a=0;d(u.blacklisted).forEach(function(t,e){var r=p(t,2),n=r[0],i=r[1];if(l(n)){var o=document.createElement("script");for(var c in"undefined"!==n.src&&o.setAttribute("src",n.src),o.setAttribute("type",i||"application/javascript"),n)c.startsWith("on")&&(o[c]=n[c]);document.head.appendChild(o),u.blacklisted.splice(e-a,1),a++}}),s.blacklist&&s.blacklist.length<1&&f.disconnect()},Object.defineProperty(t,"__esModule",{value:!0})});
</script>

Now, blocking cookies and scripts added by Google Analytics is done by the script loader at the initialization of the notice. By default, blocking is not active, to activate it you need to add the property enableGCM to the configuration configSFBXAppConsent.

::: New implementation :

<script type="text/javascript">
const configSFBXAppConsent = {
appKey: 'YOUR_APP_KEY',
enableGCM: true
}
</script>

Previously, 3 solutions were proposed to activate the blocking of Google Analytics, these 3 solutions are no longer necessary and can be removed.

Solution 1 - IAB TCF​

Simply delete the definition gtag_enable_tcf_support dans la variable window.

To delete
    <script type="text/javascript">
window['gtag_enable_tcf_support'] = true;
</script>

Solution 2 - GCM​

The old implemente of GCM must be deleted.

For that, you need to deleted the script containing Google Tag and the script to add the dataLayer variable.

To delete
    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-XXXXXXXXX-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('consent', 'default', {
'ad_storage': 'denied',
'analytics_storage': 'denied'
});
gtag('js', new Date());
gtag('config', 'UA-XXXXXXXXX-1');
</script>

It is also necessary to delete the Event listener script from your pages.

To delete
    <script type="text/javascript">
__tcfapi('addEventListener', 2, function(tcData, success) {
if (success && tcData.gdprApplies && (tcData.eventStatus === 'tcloaded' || tcData.eventStatus === 'useractioncomplete') ) {
if (tcData.purpose.consents[1]) {
gtag('consent', 'update', {
'ad_storage': 'granted',
'analytics_storage': 'granted'
})
}
}
})
</script>

Solution 3 - Google Tag Manager​

The third solution proposed was to use your tag manager to trigger Google Analytics tags based on the purpose_events sent to the dataLayer. Depending on what you have implemented in your pages, you can remove it to migrate to the new implementation.