# Migration of the CMP implementation

***

## 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.&#x20;

{% hint style="danger" %}
**TO DELETE**

```html
<!-- 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 -->
```

{% endhint %}

## 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.&#x20;

{% hint style="danger" %}
**TO DELETE**

```html
<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>
```

{% endhint %}

#### **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`.

{% hint style="info" %}
**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.&#x20;
{% endhint %}

Example of `init` callback configuration :

```html
<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 :

{% hint style="danger" %}
**TO DELETE**

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

{% endhint %}

#### **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`.

{% hint style="info" %}
**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.&#x20;
{% endhint %}

Example of callback configuration :

```html
<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.

{% hint style="danger" %}
**OLD IMPLEMENTATION**

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

{% endhint %}

{% hint style="info" %}
**NEW IMPLEMENTATION**

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

{% endhint %}

#### **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.&#x20;

{% hint style="danger" %}
**OLD IMPLEMENTATION**

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

{% endhint %}

{% hint style="info" %}
**NEW IMPLEMENTATION**

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

{% endhint %}

## 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.&#x20;

{% hint style="danger" %}
**OLD IMPLEMENTATION**

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

{% endhint %}

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

{% hint style="success" %}

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

{% endhint %}

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:

```html
<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.

[How to implement GCM](https://docs.sfbx.io/configuration/step-3-notice-implementation-web-app-tv/web-cmp/setting-up-google-consent-mode-v2-for-google-analytics-and-google-ads)

### Implementing our CMP using Google Tag Manager

One of the 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 : [Install AppConsent with Google Tag Manager](https://docs.sfbx.io/configuration/step-3-notice-implementation-web-app-tv/google-gtm/install-appconsent-with-google-tag-manager)
