Cómo ver las URLs renderizadas por Google en Google Analytics

Publicado por Lino Uruñuela el 1 de febrero del 2021

Desde hace unos cuántos años Google está produciendo grandes avances en su capacidad rastrear y obtener el contenido cargado por JavaScript, tal como lo haría un usuario navegando desde un dispositivo móvil. Para ello deduzco que ha debido hacer grandes cambios en su propia infraestructura ya que los recursos necesarios para realizar el renderizado del contenido conlleva un aumento muy considerable de los costes de Google.

Si antes para valorar esa página y decidir si añadirla o no a su índice le bastaba con acceder a la URL de la que obtenía el código HTML (y las imágenes que en ese código encontraba), ahora tiene que acceder tanto a la URL, como a las imágenes, como a todos los demás recursos (ficheros .js,, hojas de estilo .css, fuentes de texto, etc), es lo que fue llamado "Segunda Ola de Indexación". Y no solo eso, sino que tiene que ejecutar un navegador para renderizar y poder obtener lo mismo que obtendría un usuario desde un dispositivo móvil.

Aunque sabemos que actualmente Google es capaz de indexar el contenido cargado con JavaScript, también sabemos que no lo hace en todas las URLs ni con la misma frecuencia que cuando rastrea sin renderizar el contenido. Google renderiza del contenido <u>en aquellas URLs que detecta que hay una diferencia significativa cuándo lo hace ejecutando JavaScript y cuando no lo ejecuta</u>, y tiene sentido..¿para qué gastar recursos en ejecutar algo si sabe que el resultado final será el mismo que si no ejecuta esa serie de procesos necesarios para ello?.

Ya compartí cómo analizando los logs del servidor se podía saber cuándo Google renderiza una URL y así tener más visibilidad de lo que el buscador hace en nuestro site. Hoy quiero compartir una manera de monitorizar en Google Analytics qué URLs renderiza Google.

El método es relativamente sencillo, al menos para cualquier equipo técnico de un negocio y casi para cualquier webmaster que haya hecho alguna web en PHP o similar. Se compone de tres pasos,

  • El primero es añadir código JavaScript que capturará cuándo Google ha ejecutado JavaScript tal y como lo haría un usuario, y que cargará una imagen (pixel transparente) mediante JavaScript.
  • El segundo es hacer que el servidor ejecute un fichero PHP cuando se solicite la URL del pixel transparente.
  • Y el tercer paso es el fichero PHP que se ejecutará cada vez que se solicite nuestro pixel transparente.

Código JavaScript

Vamos a definir una función que se ejecuta en el evento onLoad de la página, es decir, cuando termina de cargar todos los elementos de la página. Esta función comprobará si es Google quién está ejecutando ese código JavaScript y si lo es, carga una imagen (ImagenRenderizadaGoogle.gif).

window.addEventListener("load", function(){
	//compruebo si el User Agent del usuario coincide con alguna de estas palabras
	var botPattern = "googlebot|Googlebot-Mobile|Googlebot-Image|Google favicon|Mediapartners-Google";
	var re = new RegExp(botPattern, 'i');
	var userAgent = navigator.userAgent; 

	//Si existe coincidencia, podría ser Google, así que cargamos el pixel transparente ImagenRenderizadaGoogle.gif
	if (re.test(userAgent)) {
		var client = new XMLHttpRequest();
		//A la URL del pixel transparente le paso dos parámetros, UrlOrigen y UA, con los valores de la URL actual y del User Agent del Usuario
		var ErroresURL='https://modelode.com/ImagenRenderizadaGoogle.gif?UrlOrigen='+window.location.href+'&UA='+unescape(encodeURIComponent(userAgent));
		
		client.open('GET',ErroresURL);
		client.setRequestHeader('Content-Type', 'text/plain;charset=UTF-8');
		client.send(null);
	}
});

Ahora cada vez que Googlebot acceda a la URL y ejecute JavaScript ejecutará nuestra función la cual cargará la imagen "ImagenRenderizadaGoogle.gif" añadiendo a la URL de la imagen, la URL actual del site al a que ha entrado el usuario y el User Agent de su navegador. Eso en el código de arriba lo hacemos con esta línea concreta

var ErroresURL='https://modelode.com/ImagenRenderizadaGoogle.gif?UrlOrigen='+window.location.href+'&UA='+unescape(encodeURIComponent(userAgent));

Configurar .htaccess

El siguiente paso es configurar nuestro servidor para que cuándo se solicite la URL de la imagen "ImagenRenderizadaGoogle.gif" en vez de devolver la imagen ejecute un fichero PHP (RenderizadoJS.php). Si usamos un servidor Apache, lo haríamos desde el fichero .htaccess añadiendo las siguientes líneas.

RewriteCond %{REQUEST_URI} ImagenRenderizadaGoogle.gif
RewriteRule ImagenRenderizadaGoogle.gif(.*)$ https://www.mecagoenlos.com/RenderizadoJS.php$1

Como podréis intuir voy propagando los parámetros de la URL de la imagen, así los recojo con el fichero PHP "RenderizadoJS.php".

Fichero PHP

Por último creamos un fichero PHP "RenderizadoJS.php" que será el que se ejecute cuándo alguien solicite la imagen "ImagenRenderizadaGoogle.gif". Este fichero se encargará de

  1. Comprobar mediante reverse DNS si realmente es Google o es Fake que tiene el User Agent como el de Google
  2. Identificar el tipo de bot que es, así sabremos si es Googlebot Mobile, o Images, o Ads, etc
  3. Se envia a Google Analytics un evento dónde asignamos
    • Categoría del evento: "RenderizadoGooglebot"
    • Acción del evento: URL renderizada , que el referer de la imagen
    • Etiqueta del evento: En este campo concateno el User Agent del usuario, la IP de Google y si es "Real" o es un "Fake". La IP y el User Agent los añado para tenerlo a la vista y así poder estar seguro que estaba identificando bien a Google.

      *OjO, la IP solamente la guardé durante un día para comprobar que funcionaba el código, no vaya a ser que incumplamos la ley de protección de datos....
 php
header("Pragma-directive: no-cache");
header("Cache-directive: no-cache");
header("Cache-control: no-cache");
header("Pragma: no-cache");
header("Expires: 0");
$src = $_SERVER['HTTP_REFERER']; 
$UA=$_GET["UA"]; 
$tipo = getimagesize("ImagenRenderizada.gif");
		$imagen = "ImagenRenderizada.gif"; 

//Función que comprobará si realmente es Googlebot o es un bot Fake
function comprobarGoogle($Ip){

		$hostname=gethostbyaddr($Ip);    
		$ip_by_hostname=gethostbyname($hostname);   
		if(preg_match("/googlebot/i",$hostname))
		if ($ip_by_hostname == $Ip)
			return true;
		else
				return false;
		
		else
				return false;
}

if(comprobarGoogle($_SERVER['REMOTE_ADDR']))
	$esGoogle="Real";
else
	$esGoogle="Fake";

//No solo queremos saber que es Google sino qué tipo de bot es, Mobile, Imagenes, Ads...
$botname="inicial";
$bots = array('Mediapartners-Google[ /]([0-9.]{1,10})' => 'Google Mediapartners',
	'Mediapartners-Google' => 'Google Mediapartners',
	'Googl(e|ebot)(-Image)/([0-9.]{1,10})' => 'Google Image',
	'Googl(e|ebot)(-Image)/' => 'Google Image',
	'^gsa-crawler' => 'Google',
	'Googl(e|ebot)(-Sitemaps)/([0-9.]{1,10})?' => 'Google-Sitemaps',
	'GSiteCrawler[ /v]*([0-9.a-z]{1,10})?' => 'Google-Sitemaps',
	'Googl(e|ebot)(-Sitemaps)' => 'Google-Sitemaps',
	'Mobile.*Googlebot' => 'Google-Mobile',
	'^AdsBot-Google' => 'Google-AdsBot',
	'^Feedfetcher-Google' => 'Google-Feedfetcher',
	'compatible; Google Desktop' => 'Google Desktop',
	'Googlebot' => 'Googlebot');

foreach( $bots as $pattern => $bot ) {
if ( preg_match( '#'.$pattern.'#i' , $UA) == 1 )
{
	$botname = preg_replace ( "/\\s{1,}/i" , '-' , $bot );
	break;
}
}
//con esta clase enviaremos los datos a Google Analytics mediante un evento
class BotTracker  {
	
	static function track($s, $params)
			$bot = "";
			$data = array( 
				'v'	=> 1, 
				'tid'	=> 'UA-XXXXXX-4',
				'cid'	=> self::generate_uuid(), 
				't'	=> 'event',
				'dh'	=> $s['HTTP_HOST'], 
				'dl'	=> $s['REQUEST_URI'], 
				'dr'	=> $s['HTTP_REFERER'],	
				'dp'	=> $s['REQUEST_URI'], 
				'dt'	=> $params['page_title'], 
				'ck'	=> $s['HTTP_USER_AGENT'], 
				'uip'	=> $s['REMOTE_ADDR'],
				'ni'	=> 1,
				'ec'	=> 'RenderizadoGooglebot',
				'el'	=> $params['UA']." -" .$params['botname']." - ".$params['esGoogle'],
				'ea'	=> $params['URLrenderizada']
			);
			
			$url = 'http://www.google-analytics.com/collect';
			$content = http_build_query($data); 
	
			$ch = curl_init();
			curl_setopt($ch, CURLOPT_USERAGENT, $s['HTTP_USER_AGENT']);
			curl_setopt($ch, CURLOPT_URL, $url);
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
			curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0);
			curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 0);
			curl_setopt($ch, CURLOPT_TIMEOUT_MS, 0);
			curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/x-www-form-urlencoded'));
			curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
			curl_setopt($ch, CURLOPT_POST, 1);
			curl_setopt($ch,CURLOPT_ENCODING , "gzip");
			curl_setopt($ch, CURLOPT_POSTFIELDS, $content);
			$result = curl_exec($ch);
			$info= curl_getinfo($ch);
			curl_close($ch);
		}
		static private function generate_uuid() {
		
		return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
			mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
			mt_rand( 0, 0xffff ),
			mt_rand( 0, 0x0fff ) | 0x4000,
			mt_rand( 0, 0x3fff ) | 0x8000,
			mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
		);
	}
}
 BotTracker::track($_SERVER, array("page_title"=>"Renderizado JS Google","URLrenderizada"=>$src,"esGoogle"=>$esGoogle,"botname"=>$botname,"UA"=>$UA));
?>


Ver las URLs renderizadas por Google en Google Analytics

Y ahora podemos ver en Google Analytics cada URL que renderiza Google. Como veréis no es contado como un usuario activo en el site, eso es porque hemos añadido el parámetro "nonInteraction" ('ni' en el protocolo de medición) por lo que el evento no generará interacción.

URLs renderizadas por Google usando JavaScript

Y si hacemos click en la categoría del evento "RenderizadoGooglebot" veremos el User Agent, la IP y si lo hemos identificado como Real o como Fake

Seguimiento en Google Analytics de las URLs que Googlebot renderiza

 

 



Últimos posts

Últimos comentarios


JaviLazaro
Ya me has dado la necesidad de crear un comaando en bash para hacer estas cosas. Gracias Lino por estos tips
Post: Obtener KWs de varias fuentes usando la línea de comandos

Señor Muñoz
Lino, el 11% más de clicks y el 47% más de impresiones diarias ¿es algo constante o depende de cada sitio web?
Post: Diferencias entre la exportación de datos de Search Console usando BigQuery o usando la API

Carlos
Hola En mi blog tengo artículos atemporales (es decir, no caducan nunca, de manera que sirve para quien lo lea hoy o lo lea dentro de 5
Post: Tratamiento de urls que tienen un tiempo de vida muy corto

Profe Ray
Veo que hay comentarios de hace 5 años y de hace 3 años. ¿Habrá algun post actualizado sobre este tema o sigue funcionando? Lo cierto es
Post: Cómo cargar css y js y no bloquear la carga de contenido

Pepe
Muchas gracias por el articulo!! Muy buena información.
Post: Qué es ofuscar enlaces y cómo mejora el enlazado interno

María
Sí, he buscado el archivo robots.txt y todo está correcto. La última versión vista con error fue el 08/11/2021 y la última vez que el
Post: Errores críticos originados por el robots.txt

Lino
@María un placer verte por aquí :) Lo primero, a veces, con el robots.txt no se puede "forzar" a que lo rastree, si tu site no es muy p
Post: Errores críticos originados por el robots.txt

María
Hola Lino, tengo el mismo problema. El probador de robots de google me indica: "Error al obtener el archivo robots.txt Tienes un archivo ro
Post: Errores críticos originados por el robots.txt

Mario
Estoy tratando de vincular los datos en Google Data Studio y he combinado los datos de la tabla "Impresión del sitio" con "Impresión de UR
Post: Datos incoherentes y cálculo de la posición media en Search Console

José B. Moreno Suárez
Yo hace tiempo que agrupaba con stemmers. Ahora, además, comparo con un proceso las keywords que aportan impresiones a una URL determinada
Post: Clustering de keywords SEO en Google Search Console - Parte II