Migration of the CMP implementation
Since version 32.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.
New implementation
The code to be implemented in your website is provided under each notice in the configuration interface and can be easily copied using the "Copy" button.
All that remains is to paste the code into the <head>
section of your website.
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.
To delete
<script type="text/javascript">
__tcfapi('init', 2, console.log, {
appKey: 'YOUR_APP_KEY',
url: 'https://collector.appconsent.io',
// 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 :
To delete
<script type="text/javascript">
__tcfapi('show', 2, console.log, {
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>
GCM ( Google Consent Mode v2 )
Please go tho this page to get last instructions to use Google Consent Mode v2 with our CMP.
Implementing our CMP using 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.
For more information, see page : Installer Appconsent avec Google Tag Manager