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


Lino
Hola Marcos, muy buena observación y sí, es tal como dices, o al menos yo percibo eso. El otro día lo comenté en el evento de ClickSeo
Post: Links y experimentos

Marcos
Hola Lino, gracias por tu excelente Blog Estuve replicando tu experimento, y vi lo siguiente: > Hice 3 pruebas, y no puedo posicionar co
Post: Links y experimentos

Lino
Hola @RicOriFra sí lo hay :), al vídeo sobre Search Console en el SEonthebeach
Post: Logs y Big Data

Lino
Hola @davidzslv sí me aparecieron, pero no siempre :s. Creo funciona igual que desde el Inspector, es decir, cuando quiere la indexa y cuá
Post: Solicitar indexación de una URL usando API Indexing + API Explorer

David
Estupendo, es justo lo que necesitaba, ¿al final te aparece en las serps?
Post: Solicitar indexación de una URL usando API Indexing + API Explorer

Lino
Hola @acoutin te estoy usando de pruebba, esta será la última :)
Post: Google podria no querer el HTML de una URL

Lino
@Pedro Amador ¿y funciona bien?
Post: Solicitar indexación de una URL usando API Indexing + API Explorer

Pedro Amador
¡Excelente truco Lino! Ya ha pasado a estar en mi rutina del día a día.
Post: Solicitar indexación de una URL usando API Indexing + API Explorer

Adrian Coutin
muy bueno Lino, nos indica un elemento, de los tantos, en la optimización de googlebot, no trabajar en vano... ;-) ciao
Post: Google podria no querer el HTML de una URL

Ricardo
Hola, Hay vídeo de la charla de Seonthebeach? saludos,
Post: Logs y Big Data