Recientemente Publiqué un artículo sobre cómo configurar un prueba de impacto por el “efecto parpadeo” omnipresente en las herramientas de prueba A/B del lado del cliente. Asegúrese de consultar ese artículo primero para obtener un contexto de lo que vamos a hablar aquí.
En este breve seguimiento, le mostraré cómo medir el tiempo promedio de la fragmento antiparpadeo Retrasar la visibilidad de la página, si resolve implementar el fragmento. La metodología es muy related.
Si recuerdas, el fragmento antiparpadeo se esconde toda la página mientras espera que se cargue el contenedor de Optimize. Así que mediremos cuánto tiempo tardó la página en mostrarse. La visibilidad se restaura si el contenedor de Optimize se carga correctamente o si la carga finaliza en un tiempo de espera (4 segundos de forma predeterminada).
La prueba a continuación se ejecuta dividiendo el 50% del tráfico hacia el fragmento de optimización asíncrono y el 50% del tráfico hacia el Etiqueta de optimización del Administrador de etiquetas de Google.
estamos usando Google Analytics: Aplicación + Internet Con su maravillosa Exportación de BigQuery para el análisis. Usaremos Google Tag Supervisor para recopilar y enviar los datos.
X
El boletín informativo de Simmer
Suscríbete a la Boletín informativo de Simmer ¡Para recibir las últimas noticias y contenidos de Simo Ahava en tu bandeja de entrada de correo electrónico!
Modificar la plantilla de página
Necesitas editar el plantilla de página. El fragmento antiparpadeo debe se puede agregar directamente a la plantilla de página y también debemos escribir la lógica que determina si el usuario debe ver el fragmento de Optimize o si Optimize debe cargarse a través de Google Tag Supervisor.
En el mismo arriba del aspect in your experiment pages, add the next HTML block:
<model>.async-hide { opacity: 0 !vital} model>
<script>
(perform() {
// Modify the optimizeId to match your Optimize container ID, gtmId
// to match your GTM container ID, and dataLayerName to match the title
// of the dataLayer array in your website.
var optimizeId = 'GTM-NGM64B',
gtmId = 'GTM-PZ7GMV9',
dataLayerName = 'dataLayer',
hideObj = {},
hideGTMId = Math.random() < 0.5 ? optimizeId : gtmId;
hideObj(hideGTMId) = true;
// Helper to deal with the dataLayer.push()
var dPush = perform(standing) {
window(dataLayerName).push({
occasion: 'optimize_anti_flicker_test',
milestones: {
antiFlickerStart: window(dataLayerName).conceal.begin,
antiFlickerEnd: new Date().getTime(),
testStatus: standing
}
});
};
// MODIFIED anti-flicker snippet
(perform(a,s,y,n,c,h,i,d,e) {
s.className + = ' ' + y;
h.begin = 1 * new Date;
h.finish = i = perform(){
clearTimeout
s.className = s.className.change(RegExp(' ?' + y), '')
};
(a(n) = a(n) || ()).conceal = h;
var t = setTimeout(perform() {
dPush('timeout');
i();
h.finish = null;
}, c);
h.timeout = c;
})(window, doc.documentElement, 'async-hide', dataLayerName, 4000, hideObj);
// Decide the place to load Optimize from (inline vs. GTM)
if (hideGTMId === optimizeId) {
var el = doc.createElement('script');
el.src = 'https://www.googleoptimize.com/optimize.js?id=' + optimizeId;
el.addEventListener('error', perform() {
dPush('optimizeSnippetError');
window(dataLayerName).conceal.finish && window(dataLayerName).conceal.finish();
});
doc.head.appendChild(el);
} else {
window(dataLayerName).push({
gtmOptimize: true
});
}
// Configure the Optimize callback
perform gtag() {dataLayer.push(arguments)};
gtag('occasion', 'optimize.callback', {
callback: perform() {
dPush(hideGTMId === optimizeId ? 'optimizeSnippet' : 'gtmTag');
}
});
})();
script>
Solo debe agregar este fragmento en las páginas que realmente ejecutan el experimento, para asegurarse de no recopilar accidentalmente mediciones de páginas que en realidad no ejecutan Optimize.
En el primer bloque de variables, asegúrese de actualizar optimizeId
, gtmId
y dataLayerName
para reflejar su ID de Optimize, ID de contenedor de Google Tag Supervisor y nombre de la dataLayer
matriz, respectivamente.
var hideGTMId = Math.random() < 0.5 ? optimizeId : gtmId;
elige aleatoriamente (50 % de probabilidad) si carga Optimize utilizando el fragmento en línea asincrónico o mediante una etiqueta de Google Tag Supervisor.
El fragmento antiparpadeo es modificado En esta versión, el cambio principal es que si Cuando se agota el tiempo de espera (de forma predeterminada, 4000 milisegundos después de que se ocultó la página), se dataLayer.push()
se llama con esta información. Por este motivo, otra modificación del fragmento es detener el contador de tiempo de espera en caso de que la página no esté oculta (para evitar que el tiempo de espera se informe erróneamente a dataLayer
):
h.finish = i = perform() {
clearTimeout
...
}
var t = setTimeout(perform() {
dPush('timeout');
...
}, c);
El siguiente bloque comprueba si Optimize debe cargarse mediante el fragmento o mediante GTM.
// Decide the place to load Optimize from (inline vs. GTM)
if (hideGTMId === optimizeId) {
var el = doc.createElement('script');
el.src = 'https://www.googleoptimize.com/optimize.js?id=' + optimizeId;
el.addEventListener('error', perform() {
dPush('optimizeSnippetError');
window(dataLayerName).conceal.finish && window(dataLayerName).conceal.finish();
});
doc.head.appendChild(el);
} else {
window(dataLayerName).push({
gtmOptimize: true
});
}
Si el fragmento en línea gana el sorteo, el elemento Optimizar se agrega a la página junto con un error
oyente que muestra la página en caso de que haya un error al cargar Optimize (por ejemplo, el usuario está bloqueando la carga del script).
Si Optimize se carga a través de Google Tag Supervisor, entonces la clave gtmOptimize
es empujado a dataLayer
con el valor true
Esto luego se utiliza como condición de activación para la etiqueta Optimizar.
Tan pronto como se cargue el contenedor de Optimize o Google Tag Supervisor, o el fragmento antiparpadeo alcance su tiempo de espera, o haya un error al cargar Optimize, un dataLayer.push()
ocurre con el siguiente contenido:
{
occasion: 'optimize_anti_flicker_test',
milestones: {
antiFlickerStart: window(dataLayerName).conceal.begin,
antiFlickerEnd: new Date().getTime(),
testStatus: standing
}
}
Aquí, standing
es uno de gtmTag
(si Optimize se cargó a través de Google Tag Supervisor), optimizeSnippet
(si se carga a través de Optimizar), timeout
(si se alcanza el tiempo de espera), o optimizeSnippetError
(si el fragmento de optimización encontró un error).
Una cosa a tener en cuenta es que esta configuración no no Comprueba si Google Tag Supervisor está bloqueado. Esto es algo que también puedes probar si quieres tener una concept más completa de lo que sucede con las implementaciones de tus experimentos.
Configuración del Administrador de etiquetas de Google
En Google Tag Supervisor, necesitaremos crear un Aplicación + etiqueta internet (porque queremos hacer el análisis en Gran consulta de nuevo). También necesitaremos un Activador de evento personalizado y algo Variables de capa de datos.
El gatillo
Así es como se ve el activador de evento personalizado.
Este disparador se disparará siempre que el dataLayer.push()
con los datos de prueba del fragmento se ejecuta en la página. También existe una condición para activar esta etiqueta solo en la página de inicio, ¡que puedes y debes modificar/eliminar si también estás realizando experimentos en otros lugares!.
Las variables
Vas a necesitar cuatro dataLayer
variables.
Nombre de la variable | Valor del campo “Nombre de la variable de la capa de datos” | Objetivo |
---|---|---|
DLV – hitos.testStatus | milestones.testStatus |
Uno de gtmTag , optimizeSnippet , timeout o optimizeSnippetError . |
DLV – hitos.antiFlickerStart | milestones.antiFlickerStart |
Marca de tiempo de cuándo comenzó la ocultación de la página. |
DLV – hitos.antiFlickerEnd | milestones.antiFlickerEnd |
Marca de tiempo de cuándo finalizó la ocultación de la página. |
DLV – gtmOptimizar | gtmOptimize |
Es true Si Optimize debe cargarse en una etiqueta GTM. |
Así es como se vería una variable, según la especificación de la tabla anterior:
Las etiquetas
Primero, necesitarás crear el Aplicación + etiqueta de evento internet. Asegúrate de tener un etiqueta base ¡también!
La etiqueta está configurada para activarse con el activador de evento personalizado que creamos arribay envía los valores de los tres milestones
variables a App + Internet como parámetros personalizados. Siéntase libre de cambiar las claves y los nombres de los eventos como desee.
A continuación, debemos activar la etiqueta Google Optimize. condicionalmentedependiendo de si el gtmOptimize
la clave está en dataLayer
con el valor true
.
Dado que Optimize debe ejecutarse en un secuencia de etiquetas, esto es realmente bastante complicado de hacer. Además de la propia etiqueta de Google Optimize, necesita una nueva Vista de página de Common Analytics etiqueta que solo se activa cuando gtmOptimize
es true
y necesitas bloquear tu etiqueta de vista de página regular también en esta circunstancia.
No se preocupe por la configuración de Secuenciación de etiquetas, la configura en la nueva etiqueta Vista de página que también deberá crear:
Tome nota del nuevo activador: “Todas las páginas – Antiparpadeo” es un Vista de pagina disparador con una sola condición: {{DLV - gtmOptimize}} equals true
.
Finalmente, asegúrese de bloquear su common Etiqueta Vista de página para evitar el doble conteo en páginas donde ya se activó la Vista de página específica de Optimize:
El activador de bloqueo es un activador de evento personalizado que bloquea cualquier evento si gtmOptimize
es true
:
Probar la configuración
Una vez que haya configurado todo, intente cargar la página con la modificación de la plantilla de página en el modo Vista previa. Asegúrese de ver una solicitud a App + Internet con sus parámetros personalizados implementados.
Si no funciona, verifique si hay errores en la consola del navegador. Además, asegúrese de que el contenedor de Optimize realmente se cargue y de que tenga un experimento ejecutándose en la página donde está probando.
Profundiza con BigQuery
Una vez que los datos comiencen a fluir hacia BigQuery, deberías encontrar tus eventos con una consulta como esta:
SELECT
*
FROM
`undertaking.dataset.events_202006*`
WHERE
event_name = 'optimize_anti_flicker_snippet_test'
Simplemente estamos cargando todos los hits con el optimize_anti_flicker_snippet_test
datos para obtener una visión basic de cómo se ven esos impactos.
Para obtener un recuento de los diferentes tipos de pruebas, puede ejecutar una consulta como esta:
SELECT
(SELECT worth.string_value FROM UNNEST(event_params) WHERE key = 'test_status') as test_status,
COUNT(*) as rely
FROM
`undertaking.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 realiza un recuento agregado de cada estado. Así es como se vería el resultado closing:
Finalmente, para obtener algunos promedios, puede modificar la consulta para que tenga este aspecto:
WITH milestones AS (
SELECT
(SELECT worth.string_value FROM UNNEST(event_params) WHERE key = 'test_status') as test_status,
(SELECT worth.int_value FROM UNNEST(event_params) WHERE key = 'anti_flicker_start') as anti_flicker_start,
(SELECT worth.int_value FROM UNNEST(event_params) WHERE key = 'anti_flicker_end') as anti_flicker_end
FROM
`undertaking.dataset.events_202006*`
WHERE
event_name = 'optimize_anti_flicker_snippet_test'
)
SELECT
test_status,
COUNT(*) as rely,
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 WITH...AS
El bloque crea una tabla de origen con solo el estado de la prueba y las horas de inicio y finalización del parpadeo. Luego podemos consultar esta expresión de tabla común (CTE) para obtener nuestros recuentos y promedios correctamente.
Como puedes ver, tengo una WHERE
cláusula vigente donde me aseguro de que el delta no sea superior a 5000 milisegundos. Esto se debe a que a veces el experimento resultó en deltas anormalmente altos, probablemente debido a que el contenedor Optimize estaba extremadamente tarda en cargarse y, por lo tanto, produce la hora de finalización mucho más tarde que el tiempo de espera.
Con el WHERE
cláusula, ignoramos tales deltas anormales. Podemos hacer eso porque solo nos interesa saber cuánto tiempo duró la página. ocultoy si la página está oculta durante más de 4 segundos (y cambia), el fragmento antiparpadeo la revela automáticamente.
De todos modos, esta consulta produce el siguiente resultado para mi conjunto de datos:
El tiempo promedio para que la página se oculte si el fragmento agota el tiempo de espera es de 3,8 segundos. Eso es un poco extraño ya que el tiempo de espera no debería ocurrir antes. 4000
Han pasado milisegundos. Profundizaría en ello, pero también puedo asumir que todo timeout
Sin embargo, los sucesos se ocultaron durante los 4 segundos completos.
Cuando Optimize se carga con una etiqueta de Google Tag Supervisor, la página permanece oculta durante un promedio de 964 milisegundos. Cuando se carga con el fragmento en línea asincrónico, queda oculto durante 581 milisegundos en promedio.
Resumen
Es una configuración bastante complicada, pero el objetivo no es hacer esto para cada uno de sus experimentos. Es para satisfacer su curiosidad sobre si el fragmento antiparpadeo está degradando o no la experiencia del usuario, y esto le brinda solo uno variable con la que trabajar (retraso promedio en mostrar la página).
No está exento de defectos: el cronómetro comienza cuando se ejecuta el fragmento antiparpadeo en la parte superior de cuando en realidad solo debería empezar cuando la página normalmente lo haría producir el primer elemento seen (Primera pintura con contenido).
El análisis también es imparcial: el easy hecho de conocer el retraso no es tan interesante. Lo que lo haría más significativo es ver si la duración del efecto antiparpadeo tuvo un impacto en la forma en que el usuario interactúa con el sitio. Es posible que una demora prolongada en pintar la página pueda provocar que el usuario regrese a la página anterior, ya que podría asumir que la página no funciona.
Sólo para profundizar en el tema: este artículo le mostró una metodología que podría emplear para medir el efecto de los esfuerzos de mitigación del parpadeo en las pruebas A/B del lado del cliente. el parpadeo es un problema, y saber exactamente cómo mucho de un problema es el primer paso para resolverlo.
¡Déjame saber en los comentarios si tienes sugerencias para mejorar el experimento!