Recientemente me encontré con una situación a solventar sobre este tema, las personalizaciones de Optimize cargaban posteriormente al contenido «base» mostrando el mismo en un pequeño fragmento de tiempo y empeorando notablemente la usabilidad y experiencia, por lo que tras solucionar el mismo, detallaremos como hemos batallado con este obstáculo.
Pasos para evitar el parpadeo de Google Optimize
- Implementación de Optimize desde GTM (Recomendado)
- Instaurar la secuencia de carga de Optimize en GTM
- Identificar la media de duración de carga de la página personalizada
- Implementación de Anti-Flickering con duración exacta a tu site.
Aquí veremos cómo probar la media de duración escondido en la página mientras se espera que se carguen los datos de experimentos y personalizaciones mediante Google Optimize. En esta breve exposición presentaré la forma de medir el tiempo medio del “snippet” (fragmento) que logra retardar el despliegue completo de la página si se decide realizar un despliegue de la herramienta. La metodología es muy parecida en todos los casos.
El fragmento anti parpadeo se encarga de realizar la ocultación de toda la página mientras se está a la espera de que lo contenido en Optimize resulte completamente cargado, esta funcionalidad evita el famoso «flickering» (ver la pagina base, previa carga de la personalización). Con ello estaremos midiendo cuánto tiempo la página tarda en salir de su modo de ocultación.
A todo ello decir que la visibilidad de dicha página resulta plenamente restaurada en los supuestos donde la herramienta de Optimize haya logrado realizar el proceso de cargas con éxito o, por el contrario, en el caso de que el proceso de cargas finalice por una falta adecuada de ejecución (demoras en tiempos de espera superiores a 4 segundos en su modo predefinido).
La prueba que se podrá ver a continuación se lleva a cabo ejecutando la mitad del tránsito del fragmento de optimización asíncrono y el tráfico vinculado a la etiqueta de Google Tag Manager Optimize. Para lo aquí desarrollado se está utilizando Google Analytics en su modalidad de aplicativo más Web con su fantástico elemento exportador BigQuery para llevar a cabo el proceso de análisis.
También haremos servir la herramienta Google Tag Manager, en este caso la misma será utilizada esencialmente para el recopilado de datos y para el lanzamiento de estos.
Modificación de la plantilla de la página
Lo primero que debe efectuarse es la modificación de la plantilla de la página en cuestión. Llegados a este punto el fragmento anti parpadeo deberá de ser incluido de forma directa en la misma plantilla de la página y, obviamente, se deberá determinar en dicho entorno la lógica programática que deberá determinar si el usuario deberá de visualizar el mismo fragmento o si se debe de realizar la optimización del mismo optimizador mediante la herramienta de Google Tag Manager.
El bloque HTML que debe de ir incluido en la parte superior del <head> es el siguiente:
<!-- The style declaration for the anti-flicker snippet --> <style>.async-hide { opacity: 0 !important} </style> <script> (function() { // Modify the optimizeId to match your Optimize container ID, gtmId // to match your GTM container ID, and dataLayerName to match the name // of the dataLayer array on your site. var optimizeId = 'GTM-NGM64B', gtmId = 'GTM-PZ7GMV9', dataLayerName = 'dataLayer', hideObj = {}, hideGTMId = Math.random() < 0.5 ? optimizeId : gtmId; hideObj[hideGTMId] = true; // Helper to handle the dataLayer.push() var dPush = function(status) { window[dataLayerName].push({ event: 'optimize_anti_flicker_test', milestones: { antiFlickerStart: window[dataLayerName].hide.start, antiFlickerEnd: new Date().getTime(), testStatus: status } }); }; // MODIFIED anti-flicker snippet (function(a,s,y,n,c,h,i,d,e) { s.className + = ' ' + y; h.start = 1 * new Date; h.end = i = function(){ clearTimeout(t); s.className = s.className.replace(RegExp(' ?' + y), '') }; (a[n] = a[n] || []).hide = h; var t = setTimeout(function() { dPush('timeout'); i(); h.end = null; }, c); h.timeout = c; })(window, document.documentElement, 'async-hide', dataLayerName, 4000, hideObj); // Determine where to load Optimize from (inline vs. GTM) if (hideGTMId === optimizeId) { var el = document.createElement('script'); el.src = 'https://www.googleoptimize.com/optimize.js?id=' + optimizeId; el.addEventListener('error', function() { dPush('optimizeSnippetError'); window[dataLayerName].hide.end && window[dataLayerName].hide.end(); }); document.head.appendChild(el); } else { window[dataLayerName].push({ gtmOptimize: true }); } // Configure the Optimize callback function gtag() {dataLayer.push(arguments)}; gtag('event', 'optimize.callback', { callback: function() { dPush(hideGTMId === optimizeId ? 'optimizeSnippet' : 'gtmTag'); } }); })(); </script>
En realidad, tan sólo se trataría de añadir dicho fragmento a las páginas donde se desea realizar la ejecución del experimento, y ello es así pues es la forma de garantizarse que no se realiza una corrupción de los datos mediante analíticas erróneas que resulten recogidas con páginas que estén funcionando sin Optimize.
Se debe de tener muy presente que en el primer bloque de variables debe de resultar actualizado el optimizeId, el gt-mId, así como el dataLayerName para que reseñe adecuadamente el identificador del Optimize, el contenedor del Google Tag Manager y el nombre de la matricial dataLayer.
Para realizar la elección aleatoria (un 50% de probabilidad se da uso a var hideGTMId = Math.random() < 0.5 ? optimizeId : gtmId; si es cargado Optimize con el fragmento de línea asíncrona o bien mediante una etiqueta del Google Tag Manager.
En la más reciente versión del snippet (recordemos que es la denominación habitual y convencionalmente conocida, y de uso común, por lo que en español denominamos como “fragmento”) se han incorporado algunas modificaciones. Una de las modificaciones principales tiene que ver con el tiempo de espera por defecto que se ha visto modificado, es un dataLayer.push() que hace una llamada con esta información.
Lo expuesto anteriormente lleva aparejado un cambio asociado que tiene que ver con la detención del tiempo de espera en aquellos casos de que la página no esté oculta, todo ello con la finalidad de evitar que el tiempo de espera sea erróneamente computado e informado al dataLayer:
h.end = i ? = function() { clearTimeout(t); ... } var t = setTimeout(function() { dPush('timeout'); ... }, c);
Posteriormente, con el siguiente bloque se realizará la comprobación de si el optimizador deberá de ser cargado a través del snippet (fragmento) o bien mediante GTM:
// Determine where to load Optimize from (inline vs. GTM) if (hideGTMId === optimizeId) { var el = document.createElement('script'); el.src = 'https://www.googleoptimize.com/optimize.js?id=' + optimizeId; el.addEventListener('error', function() { dPush('optimizeSnippetError'); window[dataLayerName].hide.end && window[dataLayerName].hide.end(); }); document.head.appendChild(el); } else { window[dataLayerName].push({ gtmOptimize: true }); }
En el supuesto de que el ganador sea el snippet (fragmento) el elemento Optimize se añade a la página junto con un supervisor de error que quitará de la ocultación a la página en el supuesto de que se produzca una carga errónea del Optimize. Un claro ejemplo de esto se produce cuando el usuario se encarga del bloqueo del script.
Y en el supuesto de que Optimize resulte cargado mediante GTM (Google Tag Manager) entonces la clave gtm0ptimize es llevada al dataLayer con el valor true. Después la misma resulta utilizada como disparador condicional para la etiqueta correspondiente.
Tan pronto como la optimización o el contenedor del Google Tag Manager resulte cargado, el fragmento anti parpadeo se ejecute dentro de su tiempo de espera o exista un error en la carga del Optimize, un dataLayer.push() entra en acción con el contenido siguiente:
{ event: 'optimize_anti_flicker_test', milestones: { antiFlickerStart: window[dataLayerName].hide.start, antiFlickerEnd: new Date().getTime(), testStatus: status } }
En este entorno el status es un gtmTag siempre que Optimize resulte cargado mediante Google Tag Manager), un optimizeSnippett si resulta cargado mediante Optimize, un timeout en los supuestos donde dicho “time out”, es decir donde el desbordamiento del tiempo de espera se ha producido o con optimizeSnippetError en aquellos supuestos donde en el Optimize existía corriendo un error.
Una cosa para resaltar es que en ningún caso está configuración resulta probatoria de que Google Tag Manager esté bloqueado. Quizá este sea un aspecto que también desee ser comprobada si se desea tener unas imagen más integral y holística de todo lo que está sucediendo dentro del experimento. Esto se deberá de tener presente para tomarlo en consideración en el caso de que dicha comprobación se desee llevar a cabo.
Configuración de Google Tag Manager
En Google Tag Manager hemos de crear una etiqueta Web de aplicación dado que queremos realizar un análisis en BigQuery. También resultarán necesarios un disparador de eventos personalizado y algunas variables determinadas en la capa de datos:
- El disparador:
Este activador se ejecutará en todos aquellos casos en los cuales el dataLayer.push() con los datos incluidos en la prueba del snippet (fragmento) se esté ejecutando en la página. También existe una condición para que el disparador únicamente actúe en la página principal, esto se deberá de tener presente para que resulte modificado en todos aquellos casos donde se esté ejecutando también experimentos en otros lugares
- Variables:
Se necesitarán cuatro variables básicas:
- DLV – milestones.testStatus: milestones.testStatus
- DLV – milestones.antiFlickerStart: milestones.antiFlickerStart
- DLV – milestones.antiFlickerEnd: milestones.antiFlickerEnd
- DLV – gtmOptimize: gtmOptimize
Asimismo también se deberán tenerse presentes otros aspectos como son las etiquetas:
En primer lugar, se deberá crear una etiqueta de evento de aplicación más Web. Al respecto resultará necesario cerciorarse de que se tiene también una etiqueta de base.
La etiqueta resultará definida como activador con el activador (permítase la redundancia) de eventos personalizados que han sido creados con anterioridad enviando los valores de la triple variable milestones a la app más Web como parámetros personalizados. Los nombres y claves de los eventos pueden ser cambiados al gusto.
Posteriormente, necesitaremos lanzar la etiqueta de optimización de Google de forma condicional. Todo ello dependiendo de si la clave de gtmOptimize resulta en dataLayer con el valor true.
Resulta muy completo de realizar una optimización de correr sobre una secuencia de etiqueta. Además la etiqueta de optimización en sí misma requiere de una nueva etiqueta de visualización de la página general de Analytics que sólo debe de estar “on fire” cuando gtmOptimize resulta true. Incluso en esta circunstancia debe de ser bloqueada la etiqueta de visualización de “página normal”.
Con todo configurado se debe de probar realizar la carga de la página con la modificación de la plantilla de página en el modo de previsualización. Se debe de estar seguro de estar viendo una solicitud que contenga los parámetros que se han personalizado.
En el caso de que la prueba no resulte satisfactoria y no funcione, se deberá de comprobar la consola del navegador para los errores. También se deberá realizar la comprobación de que el contenedor de Optimize ha efectuado la carga correctamente y que, por ende, el experimento está lanzado y corriendo en la página que se está deseando probar.
Profundizar con BigQuery
Cuando los datos ya están fluyendo en BigQuery se deberían encontrar los eventos propios con una consulta al estilo de la que se muestra a continuación:
SELECT * FROM `project.dataset.events_202006*` WHERE event_name = 'optimize_anti_flicker_snippet_test'
En este punto tan sólo se estarán cargando todas las peticiones de fichero con los datos optimize_anti_flicjer_snippet_test para obtener una visión general de la apariencia de estas peticiones de fichero.
Para llegar a obtener un recuento de diferentes tipos de prueba, puede ser ejecutada una consulta como la siguiente:
SELECT (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'test_status') as test_status, COUNT(*) as count FROM `project.dataset.events_202006*` WHERE event_name = 'optimize_anti_flicker_snippet_test' GROUP BY 1 ORDER BY 2 DESC
Esta consulta extrae el valor de test status de los eventos y hace un recuento agregado de cada estado. Finalmente, para llevar a obtener las medias del lugar, se puede modificar la consulta para que tenga una estructura, por ejemplo, parecida a la siguiente:
WITH milestones AS ( SELECT (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'test_status') as test_status, (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'anti_flicker_start') as anti_flicker_start, (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'anti_flicker_end') as anti_flicker_end FROM `project.dataset.events_202006*` WHERE event_name = 'optimize_anti_flicker_snippet_test' ) SELECT test_status, COUNT(*) as count, ROUND(AVG(anti_flicker_end - anti_flicker_start), 2) as average_delay_in_ms, FROM milestones WHERE anti_flicker_end - anti_flicker_start < 5000 GROUP BY 1 ORDER BY 3 DESC
El que WITH..As crea una tabla de origen con la cual están en su lugar tan sólo el estado de la prueba y el parpadeo de inicio y final. Justo a continuación se podrá consultar esta expresión en una CTE para obtener todas nuestras cuentas y medias de forma más precisa.
Como puede verse, existe incorporada una cláusula WHERE en el lugar donde resulta cerciorado que el delta no rebosa los 5000 milisegundos. Ello resulta así dado que a veces el experimento daba como resultados deltas anormalmente altos. Ello probablemente era causado por una extrema lentitud en los tiempos de carga del contenedor de optimización.
Con la cláusula WHERE se consigue realizar un ignorado de estos deltas anómalos. Esto puede ser realizado dado que tan sólo estamos interesados en los tiempos de la página que se encontraba oculta, y en el caso de que la página resultase oculta por más de 4 segundos ello es revelado por el mismo snippet (fragmento) habilitado para tal función.
Resumiendo
Todo lo anterior cierto es que resulta una organización bastante complicada y que no en todos los casos será necesario implementarlo en todos los experimentos, pero resulta muy útil para comprobar si el snippet (fragmento) anti parpadeo produce la degradación de la experiencia del usuario en algún modo o bien si ello son es así, y esto lo logra mediante una única variable de trabajo que es el retardo medio en la salida de la ocultación de la página.
No carente de defectos, el temporizador empieza en el momento en el cual el snippet (fragmento) se ejecuta en la parte superior, tal y como se ha mencionado en la parte inicial de este texto, y es entonces cuando se manera real y realista se deberá empezar a visualizar el primer elemento visible.
De forma análoga el análisis permitiría saber el impacto que tiene este efecto anti parpadeo en la forma en la que el usuario interactúa con el sitio, y ello es más así más allá de la mera medida de retardo, pues ésta por sí misma no resulta absolutamente trascendente.
Así resulta posible que mediante el tiempo de carga de la página se produzca un rebote del sumario a la página anterior dado que este usuario pueda pensar que la página no está en funcionamiento.
Tan sólo un apunte final: este texto muestra una metodología que podría llegar a ser utilizada para medir el efecto de parpadeo con la finalidad de minimizar los efectos potenciales del mismo. Y ello es absolutamente relevante, pues el parpadeo, el tiempo de carga, puede llegar a ser un problema y todas las medidas para mitigarlo, sino resolverlo resultan absolutamente interesantes.
Ante cualquier duda estoy a vuestra disposición para que se pueda contactar conmigo.
Tags :
Deja una respuesta