Bloquear manualmente las cookies en OneTrust

Si nos decantamos por la opción de «Bloqueo manual», necesitaremos programar algunas cosas. Voy a tomar de ejemplo un blog en WordPress, ya que es algo muy extendido. Tenemos que ser capaces de bloquear tanto los iframes como los scripts de terceros que puedan cargar cookies y, para ello, meteremos mano a dos tipos de iframes o scripts:

  1. Aquellos que cargamos nosotros mismos desde el <head> o <body> de nuestro sitio web y que suelen ser funcionales para todas las páginas, como por ejemplo los iframes o scripts de AddThis o Hotjar. 
  2. Aquellos que cargamos en las publicaciones o páginas del blog para un contenido concreto, como por ejemplo un vídeo de YouTube embebido. 

La programación consta de una parte en JavaScript y otra en PHP.

  • El código JavaScript de Optanon para:
    • Gestionar el consentimiento de cookies  a partir de categorización.
    • Mostrar un «Aviso de contenido bloqueado» para aquellos iframes que no sean cargados debido al uso de cookies no consentidas.
    • Botón para aceptar todas las cookies dentro del aviso y cargar todos los iframes y scripts bloqueados.
  • El código en  PHP para:
    • Reemplazar todas las URL de vídeos que tenemos de YouTube por las URL  «youtube-nocookie.com» para no depositar cookies.
    • Añadir DNT a los vídeos de Vimeo. 
    • Reemplazar todos los iframes y los scripts embebidos para adaptarlos a la notación de OneTrust.
    • Incluir el HTML para maquetar el aviso del contenido bloqueado que aparecerá al inicio de la página o publicación en función del JavaScript que gestiona el consentimiento. 

Vamos con el JavaScript colocado en <head> para todas las páginas.

<script src="https://cdn.cookielaw.org/scripttemplates/otSDKStub.js"  type="text/javascript" charset="UTF-8" data-domain-script="xx60x0f3-xxxx-485e-b378-525xa1dexxxx-test" ></script>
 
 <script type="text/javascript">
   function OptanonWrapper() {
     var regCheckPerformance = "C0002";
     var regCheckFunctional = "C0003";
     var regCheckTargeting = "C0004";
 
     if (OptanonActiveGroups.match(regCheckTargeting)) {
       var elements =       document.getElementsByClassName("optanon-category-C0004");
       loadIframe(elements);
     }
     if (OptanonActiveGroups.match(regCheckFunctional)) {
       var elements = document.getElementsByClassName("optanon-category-C0003");
       loadIframe(elements);
     }
     if (OptanonActiveGroups.match(regCheckPerformance)) {
       var elements = document.getElementsByClassName("optanon-category-C0002");
       loadIframe(elements);
     }
 
     if (OptanonActiveGroups.match(regCheckTargeting) &&
         OptanonActiveGroups.match(regCheckFunctional) &&
         OptanonActiveGroups.match(regCheckPerformance)) {
           if (document.getElementById("consentalert")) {
             document.getElementById("consentalert").remove();
           }
     }
     if (!OptanonActiveGroups.match(regCheckTargeting) &&
         !OptanonActiveGroups.match(regCheckFunctional) &&
         !OptanonActiveGroups.match(regCheckPerformance)) {
           if (document.getElementById("consentalert")) {
             document.getElementById("consentalert").classList.toggle('d-none');
           }
     }
    
     function loadIframe(elements){
       for(var i = 0; i < elements.length; i ++){
         elements[i].tagName == "IFRAME" ? elements[i].setAttribute("src", elements[i].data.data-src) : -1;
       }
     }
   }
 
   function consentallcookies() {
       if (document.getElementById("consentalert")) {
         document.getElementById("consentalert").remove();
       }
       OneTrust.AllowAll();
     }
 </script>

Fijémonos que hay dos diferencias fundamentales frente al código proporcionado en el anterior caso para el bloqueo automático.

Ya no figura la línea del script encargado del Auto-Blocking™:

<script type="text/javascript" src="https://cdn.cookielaw.org/consent/xxx81f91-xxxx-4f42-9cbc-xxxx4b0e16a3-test/OtAutoBlock.js"></script>

Añadimos el código dentro del contenedor del Optanon:

function OptanonWrapper() {
  code
}

El código completo se encargará del bloqueo de etiquetas iframes de OneTrust y añadirá un pop-up de aviso de contenido bloqueado.

Antes de entrar en materia a explicar este JavaScript, tenemos que conocer cómo OneTrust bloquea los iframes. Básicamente cambiamos el atributo src por data-src y añadimos las clases con el identificador de la categoría de cookies que use el iframe

<iframe data-src="https://www.youtube.com/yourvideo"" class="optanon-category-[Cookie ID]"></iframe>

En el caso de los scripts OneTrust cambia el type por text/plain y añade el atributo class con las clases de las categorías de cookies

<script type="text/plain" class="optanon-category-[Cookie ID]">
  code
</script>

También es posible usar la siguiente notación incluyendo más de una categoría.

<script type="text/plain" class="optanon-category-C0002-C0003-C0004">
  code
</script>

Ahora ya sabemos cómo OneTrust reconoce los iframes y scripts para ser procesados y determinar si los carga o no los carga en función del consentimiento de cookies.

Volvamos al código JavaScript inicial. En las primeras líneas definimos en las variables los identificadores para cada una de nuestras categorías establecidas en el panel de control de OneTrust.

     var regCheckPerformance = "C0002";
     var regCheckFunctional = "C0003";
     var regCheckTargeting = "C0004";

En el panel de control de OneTrust Categorizations > Categories

Las siguientes tres condicionales se encargan de cargar aquellos iframes cuya categoría de cookies haya sido activada y, por tanto, consentida (publicidad, funcional y estadística).

    if (OptanonActiveGroups.match(regCheckTargeting)) {
       var elements = document.getElementsByClassName("optanon-category-C0004");
       loadIframe(elements);
     }
     if (OptanonActiveGroups.match(regCheckFunctional)) {
       var elements = document.getElementsByClassName("optanon-category-C0003");
       loadIframe(elements);
     }
     if (OptanonActiveGroups.match(regCheckPerformance)) {
       var elements = document.getElementsByClassName("optanon-category-C0002");
       loadIframe(elements);
     }

Para cargar los iframes con categorías de cookies consentidas se hace la llamada a la función loadiframe().

    function loadIframe(elements){
       for(var i = 0; i < elements.length; i ++){
         elements[i].tagName == "IFRAME" ? elements[i].setAttribute("src", elements[i].data.data-src) : -1;
       }
     }
   }

Con el código que hemos visto ya gestionamos la carga de los iframes y, por consiguiente, las cookies que derivan de ellos. Pero ¿qué sucede con los iframes que no son cargados? Estos simplemente estarán presentes en el código HTML, pero no se procesan ni se cargan. El problema con ellos es que pueden darse espacios en blanco o que el usuario no sepa que hay contenido no cargado. Para evitar esto, primero detectaremos si hay iframes no cargados y, en ese caso, indicaremos al usuario que hay contenido bloqueado por cookies

Podemos informar al inicio de la página con un módulo de bloqueo.

ADVERTENCIA: Es importante que demos a las dos opciones (Aceptar todas las cookies, expresando que son  «todas») y un enlace para la configuración de cookies. Lo importante para el RGPD es que además del botón de Aceptar todas las cookies, se muestre otro botón de Rechazar todas o, en su defecto, uno para acceder a la configuración y poder rechazarlas.

Y ahora volviendo al código JavaScript, con las siguientes dos condiciones, nos encargaremos de gestionar el aviso de contenido bloqueado.

     if (OptanonActiveGroups.match(regCheckTargeting) &&
         OptanonActiveGroups.match(regCheckFunctional) &&
         OptanonActiveGroups.match(regCheckPerformance)) {
           if (document.getElementById("consentalert")) {
             document.getElementById("consentalert").remove();
           }
     }
     if (!OptanonActiveGroups.match(regCheckTargeting) &&
         !OptanonActiveGroups.match(regCheckFunctional) &&
         !OptanonActiveGroups.match(regCheckPerformance)) {
           if (document.getElementById("consentalert")) {
            document.getElementById("consentalert").classList.toggle('d-none');
           }
     }

La primera condicional analiza si las tres categorías de cookies: targeting (marketing, o dirigidas), functional (funcionales, o de preferencias) y perfomance (análiticas, o de estadísticas) han sido consentidas y activadas. De ser así, quita el aviso que va identificado con el id=»consentalert». 

La segunda condicional se encarga de lo opuesto, si alguna de las categorías de cookies no ha sido consentida, quita el aviso cambiando la clase d-none (display: none) que lleva de inicio. He puesto esta clase para que, por defecto,  aparezca «oculto». Si ha de mostrarse, entonces se cambiaría la clase (toggle) y pasaría al valor display: block. ¡Ojo! Esta clase d-none la tendrás que incorporar a tu CSS salvo que ya dispongas de ella a través del framework  de Bootstrap.


En el ejemplo del aviso de contenido bloqueado hay un botón para Aceptar todas las cookies, para dar vida a este botón tenemos en el código JavaScript la función cosentallcookies(), que quita el aviso del contenido bloqueado por cookies y se encarga de aceptar todas las cookies mediante el SDK JavaScript API de OneTrust y con la función OneTrust.AllowAll().

   function consentallcookies() {
       if (document.getElementById("consentalert")) {
         document.getElementById("consentalert").remove();
       }
       OneTrust.AllowAll();
     }

Este es todo el JavaScript que necesitaremos incorporar en el <head> de nuestro sitio web. En la siguiente página iremos con el PHP.

En el caso del blog en WordPress que estamos viendo necesitaremos incorporar una nueva función a nuestro fichero functions.php.

function no_cookies_replacement($html) {
   if (is_single() || is_singular('page')) {
      
       //replace youtube to youtube-nocookie
       $html = str_replace('www.youtube.com/', 'www.youtube-nocookie.com/', $html);
       $html = str_replace('youtube.com/', 'www.youtube-nocookie.com/', $html);
       $html = str_replace('youtu.be/', 'www.youtube-nocookie.com/', $html);
 
       //do not track for vimeo
       if (strpos($html, 'vimeo.com') !== false) {
           $html = preg_replace('/(player\.vimeo\.com\/video\/[0-9]*)/i', '$1?dnt=1', $html);
       }
        //OPTANON (onetrust consent)
       $html = preg_replace('~<iframe[^>]*\K(?=src)~i','data-', $html);
       $html = preg_replace_callback('/(\<iframe)[\d\D]*?\>/', function($match) {
           $class = 'optanon-category-C0002-C0003-C0004';
           $parts = explode('class="', $match[0]);
           return (count($parts) === 1) ? substr($parts[0], 0, -1).' class="'.$class.'">' : $parts[0].'class="'.$class.' '.$parts[1];
       }, $html);
 
       $html = preg_replace_callback('/(\<script)[\d\D]*?\>/', function($match) {
           $class = 'optanon-category-C0002-C0003-C0004';
           $type = 'text/plain';
           $parts = explode('type="', $match[0]);
           return (count($parts) === 1) ? substr($parts[0], 0, -1).' type="'.$type.'" class="'.$class.'">' : $parts[0].'type="'.$type.'" class="'.$class.'">';
       }, $html);
 
       //alert consent
       if (strpos($html, 'optanon-category-C0002-C0003-C0004') && !strpos($html, 'amp-')) {
           $html = '
               <div id="consentalert" class="alert alert-warning text-center m-5 d-none" role="alert">
                   <p><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Hay contenido bloqueado por el uso de cookies, para verlo puedes aceptar todas las cookies o configurarlas.</p>
                   <p><button class="btn btn-outline-primary" onclick="consentallcookies();">Aceptar todas las cookies</button></p>
                   <p><button id="ot-sdk-btn" class="ot-sdk-show-settings btn btn-outline-primary" style="border:none !important; font-weight: 100 !important;">Configuración de cookies</button></p>
               </div>
           ' . $html;
       }
 
       return $html;
   }
 
   return $html;
}
add_filter('the_content', 'no_cookies_replacement');

En la última línea, al tratarse de un WordPress, he creado un filtro que llama a la función no_cookies_replacement para el contenido que se procesa por the_content.

add_filter('the_content', 'no_cookies_replacement');

En la primera línea del código tenemos la función y como atributo que pasamos a la función la variable $html que contiene todo el contenido procesado por the_content.

function no_cookies_replacement($html) {

La segunda línea es una condicional para actuar solo en caso de que el contenido, the_content, sea un artículo o una página dentro del blog.

if (is_single() || is_singular('page')) {

También podemos usar otras condicionales de WordPress.

Ahora ya pasamos al meollo, a partir de aquí ya nos ocupamos de procesar el contenido, the_content , albergado en la variable $html, para reemplazarlo por otro evitando cookies y adaptándolo a la notación que necesita OneTrust tanto para iframes como para scripts.

<iframe data-src="https://www.youtube.com/yourvideo"" class="optanon-category-C0002"></iframe>
<script type="text/plain" class="optanon-category-C0002">
  code
</script>

En las primeras líneas nos ocupamos de reemplazar las URL de vídeos de YouTube por su sustituto «sin cookies» ( y las comillas son adrede) del dominio «youtube-nocookie.com».

$html = str_replace('www.youtube.com/', 'www.youtube-nocookie.com/', $html);
$html = str_replace('youtube.com/', 'www.youtube-nocookie.com/', $html);
$html = str_replace('youtu.be/', 'www.youtube-nocookie.com/', $html);

«youtube-nocookie» es simplemente un comienzo si no estamos especialmente interesados en los múltiples seguimientos que hace el  ecosistema de Google para marketing y retargeting. La misma opción de «youtube-nocookie» la tenemos cuando vamos a un vídeo de YouTube, en la opción de Share (‘compartir’) > Embed (‘insertar’) <> -.

Esta opción es un buen comienzo para que YouTube no almacene información sobre las personas que visitan el sitio web donde ha sido insertado un vídeo de esta plataforma, a menos que: 

  • Reproduzcan el vídeo.
  • Inicien sesión en algún servicio de Google.

Y aquí está la clave, y es que necesitamos que YouTube no cargue cookies de ninguna manera si no han sido aprobadas previamente, por lo que tenemos que bloquear el iframe de «youtube-nocookie». 

Entonces cabe pensar que este paso sobra, y en cierta forma es así, ya que si bloqueamos directamente el iframe, cortamos de raíz el problema. Sin embargo, no está de más conocer las soluciones «a medias» que nos facilitan los terceros. 

En la siguiente tabla vemos el particular uso de las cookies que hace YouTube al mostrar un vídeo desde «youtube-nocookie» y sin llegar a ser reproducido.

ChromeChrome incógnitoChrome + sesión gmail
Cookies:CONSENTNIDIDE






Están todas orientadas a publicidad dirigida y alguna relacionada con Google DoubleClick.
Cookies:NID








Al igual que el anterior bloque, también es de targeting advertising.
Cookies:SIDCCSSIDHSID SAPISIDAPISIDSID (necesaria)
NID
CONSENT__Secure-3PAPISID
Son de publicidad dirigida, excepto alguna desconocida. Casi  todas son de Google Doubleclick. 

CURIOSIDAD: Desde el momento en que accedemos a cualquier herramienta de Google, como Drive, Gmail, Analytics o incluso el mismo login del navegador Chrome, Google nos hará seguimiento con una buena colección de cookies, algunas enfocadas a la publicidad. Y aunque en una web usamos «youtube-nocookie» para embeber el vídeo, las cookies podrían cargarse igualmente en el navegador. 

CONSEJO: Cortar de raíz el problema y evitar la carga del iframes.

Con la siguiente condicional detectaremos si en nuestro contenido hay un vídeo de Vimeo y, en ese caso, mediante una expresión regular, añadimos a la URL el atributo DNT (do not track).

if (strpos($html, 'vimeo.com') !== false) {
 $html = preg_replace('/(player\.vimeo\.com\/video\/[0-9]*)/i', '$1?dnt=1', $html);
}

DNT fue un proyecto que comenzó en 2009 para navegar por Internet sin seguimientos por parte de los sitios web y sus socios publicitarios. Firefox fue el primer navegador en usarlo, posteriormente, otros como Safari, Chrome, Opera, Explorer. Seguidamente, la W3C lo intentó estandarizar, pero finalmente acabó siendo una recomendación y dio por finalizado el grupo de trabajo en 2018. Finalmente, los navegadores abandonan DNT y se habló de su muerte.

Al margen de lo que hagan los navegadores, algunas herramientas como Vimeo sí lo han incorporado como atributo para identificar si realmente el usuario no desea que carguen cookies en su dispositivo.

En el siguiente bloque de código PHP tenemos la joya de la corona, el reemplazo de todos los iframes para cortar de raíz con los problemas generados por las cookies de terceros. Con este código se adaptan los iframes a la notación de OneTrust para conseguir que, por un lado, no sean cargados y, por otro lado, los iframes sean procesados mediante el consentimiento de cookies de OneTrust.

$html = preg_replace('~<iframe[^>]*\K(?=src)~i','data-', $html);
$html = preg_replace_callback('/(\<iframe)[\d\D]*?\>/', function($match) {
   $class = 'optanon-category-C0002-C0003-C0004';
   $parts = explode('class="', $match[0]);
   return (count($parts) === 1) ? substr($parts[0], 0, -1).' class="'.$class.'">' :   $parts[0].'class="'.$class.' '.$parts[1];
}, $html);

Con la primera línea, y mediante una expresión regular, detectamos todos los iframes existentes y cambiamos su atributo src por data-src. Esto es lo que evitará que sean cargados por defecto a la hora de visualizar la página web, además de incluir las categorías de las cookies.

<iframe data-src="https://www.youtube.com/yourvideo"...

En la segunda línea, nos encargamos de añadir una clase con las categorías para que la funcionalidad del Optanon identifique que ese iframe puede ser cargado o no, dependiendo de las cookies consentidas para una categoría.

$class = 'optanon-category-C0002-C0003-C0004';

En mi caso, he puesto los identificadores para las categorías de cookies 2 (rendimiento), 3 (funcionalidad) y 4 (dirigidas). La 1 no haría falta, ya que sería para las cookies estrictamente necesarias y están permitidas para que cualquier sitio web funcione correctamente.

Si sabemos que solo insertamos un determinado iframe que carga siempre cookies de rendimiento podríamos poner:

$class = 'optanon-category-C0002';

CONSEJO: En muchos casos desconocemos qué herramientas hemos usado en el pasado, qué soluciones vamos a usar en el futuro o, incluso, aunque conozcamos bien un iframe y las cookies que carga, mañana podría el proveedor del iframe cargar otras, así que para curarnos en salud, mejor establecer las tres categorías (C0002-C0003-C0004).

Optanon OneTrust encontrará en nuestra página HTML el siguiente iframe:

<iframe data-src="https://www.youtube.com/yourvideo"" class="optanon-category-C0002-C0003-C0004"></iframe>

Si el usuario ha aceptado todas las cookies (las tres categorías necesarias C0002-C0003-C0004), entonces será el propio Optanon quien cambie el atributo data-src por src con la consiguiente carga del iframe

El código que lanzamos con la función preg_replace_callback()es suficientemente inteligente para añadir las clases con las categorías, teniendo en cuenta que un iframe puede tener ya alguna clase inicial, en cuyo caso las mantendrá. 

<iframe data_src=»https://www.youtube.com/yourvideo»» data_src=»align-center optanon-category-C0002-C0003-C0004″></iframe>

A continuación viene el reemplazo de los scripts, ya que en algunos casos es bastante común que las soluciones de terceros nos ofrezcan un script y no un iframe. Este script a veces es el que genera el iframe o, en otros casos, un pequeño fragmento de HTML o JavaScript para disponer el contenido. 

El bloqueo de los scripts lo proporciona el siguiente fragmento:

$html = preg_replace_callback('/(\<script)[\d\D]*?\>/', function($match) {
    $class = 'optanon-category-C0002-C0003-C0004';
    $type = 'text/plain';
    $parts = explode('type="', $match[0]);
    return (count($parts) === 1) ? substr($parts[0], 0, -1).' type="'.$type.'" class="'.$class.'">' : $parts[0].'type="'.$type.'" class="'.$class.'">';
}, $html);

En este caso, Optanon reemplaza el atributo type del inicial text/javascript por text/plain y añade las clases de las categorías.

<script type="text/plain" class="optanon-category-C0002-C0003-C0004"></script>

Optanon verá los scripts con la anterior notación y se encargará de procesarlos y cambiar el type cuando las cookies de las tres categorías sean aceptadas.

Finalmente, tenemos el último bloque de código:

if (strpos($html,'optanon-category-C0002-C0003-C0004') && !strpos($html,'amp-')) {
    $html = '
        <div id="consentalert" class="alert alert-warning text-center m-5 d-none" role="alert">
            <p><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Hay contenido bloqueado por el uso de cookies, para verlo puedes aceptar todas las cookies o configurarlas.</p>
            <p><button class="btn btn-outline-primary" onclick="consentallcookies();">Aceptar todas las cookies</button></p>
            <p><button id="ot-sdk-btn" class="ot-sdk-show-settings btn btn-outline-primary" style="border:none !important; font-weight: 100 !important;">Configuración de cookies</button></p>
         </div>
   ' . $html;
}

Este código se encarga de añadir, al inicio de todo, el contenido (ya sea de una publicación o de una página), el ya conocido aviso de contenido bloqueado que hemos visto anteriormente.

Fijémonos en el botón de Aceptar todas las cookies, que lleva un atributo de tipo evento onclick que dispara la función JavaScript consentallcookies()que tenemos en nuestro <head> y que anteriormente ya hemos visto en detalle. Por medio del JavaScript, este botón aceptará todas las cookies, quitará el aviso y se cargarán los contenidos bloqueados. 


Por otro lado, tenemos el enlace Configuración de cookies, que se genera por medio de un identificador ot-sdk-btn y la clase ot-sdk-show-settings, proporcionada por OneTrust, y que hemos visto dentro del panel de control en la sección de Integration > Scripts.

CONSEJO: Puedes personalizar totalmente el aspecto del botón para la Configuración de cookies, pero si pensamos en el marketing y una rápida experiencia de uso, es preferible que pongamos un enlace y no un botón. Con ello animaremos a que los usuarios acepten todas las cookies y , así, podremos cargar todo el contenido. Si la configuración fuese un botón, ya competiría con el de Aceptar todas las cookies.

CONSEJO: Para este aviso, hay que evitar el botón Rechazar cookies,  ya que muchos usuarios rechazan ver ese contenido bloqueado sin apenas leer el aviso.

Por último, no olvidemos devolver el resultado, de ahí la parte final del código:

       return $html;
   }
   return $html;

El primer retorno devuelve todos los reemplazos y acciones que hemos analizado. El segundo y último retorna el contenido sin haber actuado sobre él, ya que no ha entrado en la condicional al tratarse de otro tipo de contenido que no es ni un artículo ni una página. 

Hasta aquí hemos visto cómo bloquear iframes y scripts que sean suministradores en el contenido de artículos o páginas de nuestro blog. Pero ¿qué sucede con aquellos iframes o scripts que van incluidos en el <head> o <body>? Nuestro código en PHP solo actúa premeditadamente sobre the_content. Y este proceder es correcto, ya que si actuamos sobre todo el sitio web, entonces podemos bloquear cosas que no queremos.

Tres opciones para procesar los iframes o scripts que tenemos insertados:

  1. Cambiar manualmente los atributos de los iframes o scripts
  2. Incluir los scripts en la función OptanonWrapper de JavaScript.
  3. Gestionar los scripts mediante Google Tag Manager.

Para la primera de las opciones, supongo que tenemos en la cabecera, <head>, el script de AddThis para generar la botonera que permite al usuario compartir en redes sociales la URL que está visitando. 

<script type="text/javascript" src="//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-5f0c5e79040XXXXX"></script>

Lo cambiaremos a la notación que pueda interceptar y procesar Optanon.

<script type="text/plain" src="//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-5f0c5e79040XXXXX"  class="optanon-category-C0002-C0003-C0004"></script>

Como segunda opción, podemos incluir la inserción de scripts directamente en el OptanonWrapper, la función JavaScript en <head> que hemos visto anteriormente en detalle.

function OptanonWrapper() {
   code
Optanon.InsertScript('//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-5c5b0cf7ac7XXXXX', 'addthis', null, null, 3);
}

Si nos decantamos por la tercera opción (más profesional, ya que conviene tener centralizados estos scripts), entonces debemos gestionar por medio de GTM la carga de los iframes o scripts en relación con los identificadores de cada categoría de cookies. Para implementarlo, puedes seguir los pasos de Cookie Compliance con Google Tag Manager