Volver al Centro de conocimiento
Identidad

User-Agent y Client Hints: una identidad coherente

Cómo deben coincidir la cabecera User-Agent, Client Hints y navigator.userAgentData, por qué las sobrescrituras del framework dejan huecos y cómo fijar y comprobar una identidad.

BotBrowser Team

Documentación

Prefieres la documentación del producto mantenida?

Este artículo tiene una página equivalente en el centro de documentación. Usa los docs para el flujo canónico, las flags actuales y la referencia duradera.

Una misma identidad debe coincidir en la cabecera User-Agent, los Client Hints y navigator.userAgentData. BotBrowser alinea esas superficies, incluidas las de los workers; no puede cambiar lo que un servidor hace con esa identidad ni eximirte de mantener la versión completa alineada con la versión principal de Chromium del binario.

Resumen rápido

Compara cuatro superficies: la cadena navigator.userAgent, los Client Hints de baja y alta entropía, los valores de un Worker y las cabeceras de la solicitud. Si una difiere, quita cualquier sobrescritura de página o de CDP y deja que los flags del navegador fijen la identidad.

Contenido de esta guía

Por qué la cabecera User-Agent, Client Hints y userAgentData deben coincidir

La cabecera User-Agent es la forma más antigua que tiene un navegador de describirse ante un sitio web. Durante años fue una cadena larga que reunía el nombre del navegador, la versión completa, el sistema operativo y el motor de renderizado. Chrome ha reducido desde entonces el detalle que lleva esa cadena, y la información estructurada pasó a User-Agent Client Hints, abreviado normalmente como UA-CH. El resultado es que una misma identidad de navegador se expresa ahora en varios lugares a la vez: la cabecera de solicitud User-Agent, la familia de cabeceras de solicitud Sec-CH-UA, la cadena navigator.userAgent y la API navigator.userAgentData. BotBrowser puede mantener coherentes la cadena User-Agent, los Client Hints y los valores de navigator de un perfil en un contexto controlado; no puede cambiar lo que un servidor decide hacer con esa identidad.

Una identidad personalizada es, por tanto, tan buena como su superficie más débil. Si cambias la cadena y nada más, la cabecera dice una cosa, Sec-CH-UA dice otra y navigator.userAgentData dice una tercera. Cada superficie es válida por separado, pero juntas describen un navegador que no existe.

Esto importa tanto para la privacidad como para la simple usabilidad. La cabecera User-Agent y las pistas de baja entropía llegan con la primera solicitud, antes de que se ejecute ningún script, así que el servidor las ve antes de que la página se cargue. Las páginas y los scripts de analítica pueden leer después los mismos datos mediante JavaScript y compararlos. Cuando las respuestas difieren, la combinación es en sí misma inusual y hace que la sesión sea más fácil de distinguir. También provoca fallos cotidianos, como un servidor que elige un diseño móvil a partir de la cabecera User-Agent mientras un script lee una plataforma de escritorio en navigator.userAgentData.

Diagrama en el que una identidad configurada alimenta las cabeceras HTTP, el hilo principal, el ámbito Worker y los valores de alta entropía, seguida de una comprobación de que los cuatro coinciden

Tres grupos de lectores se encuentran con este problema con más frecuencia. Los equipos que prueban un sitio para visitantes de Android o de Edge necesitan que el navegador se describa como ese tipo de visitante en todas partes. Las personas que mantienen varias identidades de navegación separadas por motivos de privacidad necesitan que cada identidad sea estable y coherente en sí misma. Los ingenieros de soporte que reproducen la incidencia de un cliente necesitan que la reproducción lleve la misma identidad que tenía el cliente. Los tres dependen de la coincidencia entre superficies y no de un valor aislado.

Antes de cambiar nada conviene hacerse tres preguntas:

  • ¿Qué superficies informan de la identidad y cambiarán todas a la vez?
  • ¿Todos los números de versión pertenecen a la misma versión principal de Chromium?
  • ¿El resto de la configuración, como la configuración regional, la zona horaria y la ruta de red, sigue describiendo un navegador coherente?

Las superficies que deben coincidir

Los navegadores basados en Chromium se describen mediante cuatro grupos de valores. Cada uno se explica a continuación, seguido de una lista breve de las coincidencias que puedes comprobar.

La cadena User-Agent

La cabecera de solicitud User-Agent y navigator.userAgent llevan la misma cadena. En Chrome de escritorio tiene este aspecto:

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.7444.60 Safari/537.36

Con la reducción del User-Agent de Chrome, las partes de sistema operativo y versión de esta cadena se mantienen en valores genéricos y las partes menores de la versión están fijadas. La cadena se sigue enviando con cada solicitud y sigue siendo lo primero que leen la mayoría de los servidores, así que debe seguir el ritmo de los valores estructurados que sustituyeron el detalle que ya no lleva. Para el contexto de los estándares y una migración paso a paso desde el análisis del User-Agent hacia Client Hints, consulta Migración de User-Agent Reduction a Client Hints.

Las cabeceras de solicitud Client Hints

Client Hints exponen los mismos datos de forma estructurada. Las pistas de baja entropía se envían por defecto en las solicitudes:

  • Sec-CH-UA enumera tokens de marca con su versión principal, por ejemplo "Chromium";v="142", "Google Chrome";v="142", "Not:A-Brand";v="99".
  • Sec-CH-UA-Mobile indica si el navegador es móvil, por ejemplo ?0.
  • Sec-CH-UA-Platform nombra el sistema operativo, por ejemplo "Windows".

Las pistas de alta entropía solo se envían después de que un servidor las pide con una cabecera de respuesta Accept-CH:

  • Sec-CH-UA-Full-Version-List lleva las versiones completas de cada marca.
  • Sec-CH-UA-Platform-Version lleva la versión del sistema operativo.
  • Sec-CH-UA-Arch y Sec-CH-UA-Bitness llevan la arquitectura de CPU y los bits del sistema.
  • Sec-CH-UA-Model lleva el modelo del dispositivo, que importa sobre todo en móvil.

Como las pistas detalladas se envían bajo petición, una discrepancia en ellas puede pasar inadvertida hasta que un sitio las solicita. Una configuración que parece correcta en la primera carga puede contradecirse en la segunda. Para ver cómo se usan estas cabeceras y dónde se desajustan, consulta Client Hints Fingerprinting: encabezados HTTP e identidad, que compara los valores de las cabeceras con los de JavaScript en una misma sesión.

La versión de JavaScript de la misma información es navigator.userAgentData. Sus propiedades brands, mobile y platform reflejan las cabeceras de baja entropía. Los valores detallados provienen de getHighEntropyValues(), que devuelve una promesa:

navigator.userAgentData.brands;
navigator.userAgentData.mobile;
navigator.userAgentData.platform;
await navigator.userAgentData.getHighEntropyValues([
  'platformVersion',
  'architecture',
  'bitness',
  'fullVersionList',
  'model',
]);

Lo que digan las cabeceras debe decirlo también estas propiedades. La especificación define la API y los nombres de las cabeceras juntos, por eso ambas se deben leer como una sola descripción.

Ámbito de los Workers

Un worker dedicado, un worker compartido y un service worker tienen cada uno su propio objeto navigator. Un worker que informa de un User-Agent o de un userAgentData distinto del de la página que lo inició es una incoherencia clara, porque el worker pertenece al mismo navegador. Cualquier enfoque que cambie valores solo en la página y no dentro del ámbito del worker deja este hueco abierto.

Entradas GREASE y alineación de versiones

Chromium añade a la lista de marcas una entrada GREASE deliberadamente sin sentido, como "Not:A-Brand";v="99". Su texto, su versión y su posición cambian entre versiones del navegador. Su finalidad es evitar que los servidores dependan de un formato de lista fijo, así que una lista escrita a mano que acierta mal la entrada o la coloca en otro sitio se ve distinta de una real.

Los números de versión exigen el mismo cuidado. La versión principal de la cadena User-Agent, las versiones de Sec-CH-UA y las entradas de fullVersionList deben describir la misma versión de Chromium. Una versión completa 142.0.7444.60 en un sitio y una versión principal 140 en otro son una discrepancia aunque todos los nombres de marca sean correctos.

Las coincidencias que puedes comprobar

En conjunto, una identidad creíble cumple esta lista:

  1. La cabecera User-Agent coincide con navigator.userAgent.
  2. Los tokens de marca de Sec-CH-UA coinciden con navigator.userAgentData.brands.
  3. La plataforma de Sec-CH-UA-Platform coincide con navigator.userAgentData.platform.
  4. La versión principal de la cadena User-Agent coincide con las versiones de los tokens de marca de Sec-CH-UA.
  5. Las versiones completas de Sec-CH-UA-Full-Version-List coinciden con fullVersionList de getHighEntropyValues().
  6. La versión de plataforma es un valor real para el sistema operativo declarado.
  7. La arquitectura y los bits encajan con la plataforma, por ejemplo x86 y 64 en un escritorio Windows.
  8. Todos los valores son iguales en el hilo principal, en los workers y en las cabeceras de solicitud HTTP.

Por qué una sobrescritura de framework o de CDP deja huecos

Los frameworks de automatización hacen fácil cambiar la cadena. Playwright acepta una opción userAgent al crear un contexto, y Puppeteer ofrece page.setUserAgent():

const context = await browser.newContext({ userAgent: 'Custom UA String' });
await page.setUserAgent('Custom UA String');

Una sobrescritura que solo toca la cadena cambia siempre la cabecera User-Agent y navigator.userAgent; lo que ocurre con el resto depende de la llamada. Medido el 2026-10-23 con Playwright 1.58.0 y Puppeteer 24.40.0:

  • browser.newContext({ userAgent }) de Playwright también derivó metadatos de plataforma: la página y el Worker pasaron a informar la nueva plataforma, mientras que la marca y las versiones podían seguir describiendo el Chromium subyacente.
  • page.setUserAgent('Custom UA String') de Puppeteer dejó navigator.userAgentData con marcas y valores estructurados vacíos, no con los originales.

Así que no des por hecho ni «la identidad original se mantiene» ni «toda la identidad sigue a la cadena». Lee la página, el Worker y las cabeceras de la solicitud en la compilación que uses; el registro de cuatro superficies de arriba es lo que te dice en qué caso estás.

El Chrome DevTools Protocol ofrece Network.setUserAgentOverride con un objeto opcional userAgentMetadata. Es más completo, porque puede llevar marcas, plataforma y el resto de las pistas. Aun así, traslada el trabajo a ti. La lista de marcas, la entrada GREASE, las versiones completas y los campos de plataforma hay que escribirlos a mano y mantenerlos alineados con la cadena. La sobrescritura se aplica al objetivo al que se envió, de modo que cada página y cada worker necesitan su propia llamada, y una lista correcta para una versión de Chromium queda obsoleta en la siguiente.

Establecer cabeceras adicionales tiene la misma forma de problema. Una regla que reescribe Sec-CH-UA en la red cambia la solicitud, pero no lo que devuelve navigator.userAgentData dentro de la página. La identidad difiere entonces entre la capa de red y la capa de scripts. Cómo definir cabeceras de solicitud adicionales en BotBrowser mediante un flag, un perfil o CDP se explica en Encabezados HTTP personalizados en BotBrowser: indicador, perfil o CDP.

Estos son límites generales de los enfoques que reescriben una superficie cada vez. Una regla de cabeceras, una sobrescritura de cadena y un script que edita una propiedad cubren cada uno su propia superficie, y nada garantiza que las superficies sigan coincidiendo después. La solución fiable es elegir la identidad una sola vez y hacer que todas las superficies deriven de esa elección.

Fijar un User-Agent personalizado en BotBrowser

Un perfil de BotBrowser ya aporta una base coherente. Contiene una cadena User-Agent, valores de Client Hints y campos de userAgentData que coinciden entre sí, así que cargarlo evita configurar cada superficie por separado. Los flags siguientes solo son necesarios cuando una prueba debe representar un entorno distinto al perfil guardado.

El flag --user-agent recibe la cadena en bruto y trabaja junto con un conjunto de flags --bot-* que describen la parte estructurada. El User-Agent personalizado y el control completo de userAgentData requieren una licencia ENT Tier3:

FlagControlaEjemplo
--user-agentLa cadena User-Agent en brutoMozilla/5.0 (Linux; ...)
--bot-platformLa plataforma en userAgentDataWindows, Android
--bot-platform-versionLa versión del sistema operativo13, 10.0
--bot-modelEl modelo del dispositivo, sobre todo en móvilSM-G991B
--bot-architectureLa arquitectura de CPUx86, arm
--bot-bitnessLos bits del sistema32, 64
--bot-mobileEl indicador móvil en userAgentDatatrue, false

El valor de --user-agent puede contener marcadores que se sustituyen al iniciar el navegador. {platform}, {platform-version}, {model}, {architecture} y {bitness} toman su valor de los flags --bot-* correspondientes, y {ua-full-version}, {ua-major-version} y {brand-full-version} lo toman de los flags de versión. Usar marcadores mantiene la cadena y los valores estructurados ligados a una sola fuente, de modo que no puedes cambiar el modelo en un sitio y olvidarte del otro.

Dos flags de apoyo fijan las versiones. --bot-ua-full-version (ENT Tier2) fija la versión completa de Chromium, y --bot-brand-full-version (ENT Tier2) fija la versión propia de la marca para marcas como Edge. La documentación recomienda mantener --bot-ua-full-version alineado con la versión principal de Chromium de tu binario de BotBrowser. Para saber cómo se elige y se comprueba la marca en Chrome, Edge y Brave, consulta Cambio de marca: Chrome, Edge, Brave, Opera, que explica cómo fijar la marca al iniciar.

Una identidad Android en un equipo de escritorio se ve así:

chrome --bot-profile="path/to/android-profile.enc" \
       --user-agent="Mozilla/5.0 (Linux; Android {platform-version}; {model}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/{ua-full-version} Mobile Safari/537.36" \
       --bot-platform=Android \
       --bot-platform-version=13 \
       --bot-model=SM-G991B \
       --bot-mobile=true \
       --bot-ua-full-version=142.0.7444.60

BotBrowser sustituye {platform-version}, {model} y {ua-full-version} por los valores de los flags y después genera el navigator.userAgentData correspondiente, las marcas con una entrada GREASE correcta, los valores de alta entropía y las cabeceras de solicitud de Client Hints. Según la documentación de BotBrowser, el resultado se mantiene coherente en el hilo principal, los Workers y las solicitudes HTTP.

Una identidad de escritorio Windows sigue el mismo patrón con otros valores:

chrome --bot-profile="path/to/windows-profile.enc" \
       --user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/{ua-full-version} Safari/537.36" \
       --bot-platform=Windows \
       --bot-platform-version=10.0 \
       --bot-architecture=x86 \
       --bot-bitness=64 \
       --bot-mobile=false \
       --bot-ua-full-version=142.0.7444.60

Playwright y Puppeteer pasan los mismos flags mediante su opción args, no mediante un ajuste userAgent del framework. Pasa los flags mediante args, como hacen los ejemplos de la documentación. Para cambiar la propia marca, que es un control ENT Tier2 distinto, consulta el artículo sobre marcas enlazado al final.

Verificar la identidad en la página, en un worker y en la solicitud

Después de iniciar, puedes verificar el resultado dentro del navegador sin herramientas adicionales. El objetivo es leer la misma identidad en cada uno de los tres lugares donde un sitio puede leerla.

Empieza por la página. Abre las herramientas de desarrollo en cualquier página y ejecuta estas líneas en la consola:

navigator.userAgent;
navigator.userAgentData.brands;
navigator.userAgentData.platform;
await navigator.userAgentData.getHighEntropyValues([
  'platformVersion',
  'architecture',
  'bitness',
  'fullVersionList',
  'model',
]);

Después comprueba la solicitud. Abre el panel Red, selecciona una solicitud HTTPS de nivel superior y lee sus cabeceras. Las cabeceras User-Agent, Sec-CH-UA, Sec-CH-UA-Mobile y Sec-CH-UA-Platform deben coincidir con lo que imprimió la consola. Las cabeceras detalladas, como Sec-CH-UA-Full-Version-List, aparecen solo cuando el sitio las pide con Accept-CH, así que su ausencia en la primera solicitud es normal y no es una discrepancia.

Por último, comprueba el ámbito de los workers. Este fragmento breve inicia un worker dedicado a partir de un blob e imprime lo que informa el worker:

const worker = new Worker(
  URL.createObjectURL(new Blob(['postMessage([navigator.userAgent, navigator.userAgentData.platform])']))
);
worker.onmessage = event => console.log(event.data);

Los dos valores que imprime el worker deben coincidir con los de la página. Si tus páginas usan un service worker, inspecciónalo desde el panel Aplicación y ejecuta las mismas dos expresiones en su consola.

Cuando algo parece incorrecto, el síntoma suele señalar la causa:

SíntomaCausa probableQué ajustar
Un marcador como {model} aparece literalmente en la cadenaFalta el flag --bot-* correspondienteDefine --bot-model o quita el marcador
La cabecera dice Android pero userAgentData.platform dice WindowsNo se definió --bot-platformAñade --bot-platform=Android y los demás flags de plataforma
Las versiones de Sec-CH-UA difieren de la cadena User-AgentEl flag de versión no coincide con la versión principal de ChromiumAlinea --bot-ua-full-version con la versión de Chromium del binario
La cadena cambió pero las pistas no la siguieronLa cadena se fijó mediante una opción del frameworkPásala con --user-agent dentro de args
El worker informa de valores distintos a los de la páginaUn script o sobrescritura de la página cambió solo la páginaQuita la sobrescritura de página y conserva los flags del navegador

Repite la comprobación tras cada cambio de perfil, de versión de Chromium o de flags de identidad, porque cada uno de ellos puede mover una superficie sin mover las demás. Una comprobación superada muestra que el navegador es coherente consigo mismo. No muestra cómo tratará una web concreta la sesión, porque los sitios combinan muchas señales y cambian sus propias reglas con el tiempo.

Elegir valores y planificar según los límites

Los flags hacen que las superficies coincidan entre sí. No eligen valores sensatos por ti, así que la calidad del resultado depende de lo que introduzcas:

  • Usa versiones realistas y actuales. Una versión de navegador que casi nadie sigue usando es inusual por sí sola, así que sigue la versión principal de Chromium de tu binario.
  • Elige valores que encajen entre sí. Una plataforma, una versión de plataforma, un modelo, una arquitectura y unos bits deben describir un tipo de dispositivo real.
  • Haz coincidir los ajustes del entorno. La identidad, la zona horaria, la configuración regional, el idioma y la ruta de red deben describir el mismo tipo de visitante.
  • Mantén una sola identidad durante toda la vida de una sesión o cuenta. Cambiar la cadena entre visitas al mismo sitio crea un historial incoherente.
  • Repite la verificación tras actualizar el navegador o los perfiles.

Un perfil cargado ya trae una identidad coherente, por lo que omitir --user-agent evita trabajo adicional. Solo presenta otra identidad cuando la prueba lo exige, como al reproducir en un escritorio una incidencia exclusiva de Android; después revisa cada superficie. Cada sobrescritura añade un valor que debe permanecer alineado, así que limita el cambio al requisito de la prueba.

Algunas preguntas prácticas surgen con frecuencia:

  • ¿Qué pasa si defino --user-agent sin los flags --bot-* correspondientes? Define el flag --bot-* correspondiente a cada marcador que uses; por ejemplo, {model} requiere --bot-model. La documentación recomienda usar la sintaxis de marcadores junto con los flags correspondientes.
  • ¿La identidad llega a los workers? Sí. Según la documentación, los valores se mantienen coherentes en el hilo principal, los Workers y las solicitudes HTTP, y la verificación anterior te permite confirmarlo.
  • ¿Necesito licencia para una configuración solo con perfil? No intervienen flags personalizados: se usan los valores capturados en el perfil. El control completo de userAgentData con un User-Agent personalizado necesita una licencia ENT Tier3.
  • ¿Una identidad personalizada cambia las funciones del navegador? Los flags cambian los valores de identidad que se informan. No añaden funciones que el navegador subyacente no tenga, así que prueba las páginas que te importan tras un cambio.

BotBrowser soporta un --user-agent personalizado con marcadores, junto con --bot-platform, --bot-platform-version, --bot-model, --bot-architecture, --bot-bitness y --bot-mobile, y genera marcas de Client Hints, valores de alta entropía y cabeceras HTTP coincidentes que se mantienen coherentes en el hilo principal, los Workers y las solicitudes. Eso sustituye la contabilidad manual descrita arriba por una sola identidad que verificar en lugar de varias. BotBrowser no puede hacer que un sitio acepte una identidad elegida, no sustituye la elección de valores de versión realistas y actuales, y un User-Agent personalizado con control completo de userAgentData requiere una licencia ENT Tier3.

Para cambiar la marca del navegador, consulta Desajustes de marca de navegador en Chrome, Edge y Brave. Para ver cómo usan los sitios web las Client Hints, consulta Client Hints Fingerprinting: encabezados HTTP e identidad. Para combinar la identidad con ajustes geográficos, consulta Zona horaria, configuración regional e idioma.

Qué añade frente a la página de referencia

La página de referencia enumera la opción User-Agent y los flags de apoyo. No te da un registro que puedas comparar entre dos lanzamientos, y una discrepancia se lee mal sin él, porque una sobrescritura de framework oculta qué superficie se movió realmente.

SuperficieDónde se leeQué señala una discrepancia
PáginaConsola de la páginaLa sobrescritura actuó pero dejó un conjunto incompleto
WorkerConsola del WorkerUn arreglo a nivel de página que no llegó al Worker
SolicitudPanel Red, peticiónUna reescritura en el cable que la página no ve
HintsgetHighEntropyValues() en la páginaUna política de permisos o una sobrescritura que dejó incompleto el conjunto de alta entropía

Guarda las cuatro lecturas antes de cambiar el perfil. Ejecuta estas tres expresiones en la página, luego las mismas dos en un Worker, y después abre el panel Red y copia las cabeceras de la petición en el mismo archivo. Mantén un archivo por lanzamiento, nombrado según mode, y compara los dos archivos en vez de repetir la comprobación de memoria.

// la página y el Worker aceptan esta forma
const identity = {
  ua: navigator.userAgent,
  brands: navigator.userAgentData?.brands?.map(b => `${b.brand}/${b.version}`),
  mobile: navigator.userAgentData?.mobile,
  platform: navigator.userAgentData?.platform,
};
identity.high = await navigator.userAgentData.getHighEntropyValues([
  'platformVersion',
  'architecture',
  'bitness',
  'fullVersionList',
]);
console.log(JSON.stringify(identity));

Si el registro de la página y el del Worker difieren, algo por debajo de la página está reescribiendo la identidad. En un framework que solo parchea el hilo principal, esa es la causa habitual; en la compilación que estás probando, confírmalo desactivando la sobrescritura y repitiendo las dos lecturas, porque otros mecanismos pueden producir la misma división. Mientras la sobrescritura siga ahí, ajustar flags no cerrará la brecha. Si las cabeceras de la solicitud y el registro de la página difieren, el cambio ocurrió solo en el cable. Si high está vacío, revisa la política de permisos ch-ua-high-entropy-values de esa página: getHighEntropyValues() solo devuelve los valores donde la política los permite. Una página que nunca pidió al servidor las pistas detalladas puede devolverlos igualmente, y una página que envió Accept-CH puede rechazar la API, así que comprueba por separado la API y las cabeceras de la solicitud en lugar de concluir que la configuración está rota.

Fuentes

Conclusión práctica

Compara la cadena, userAgentData, el Worker y las cabeceras como un único registro derivado de la misma versión. Ante una discrepancia, elimina primero la sobrescritura de página y vuelve a medir esos cuatro puntos antes de tocar el perfil.

#user agent#client hints#Identity#Ua-Ch#privacidad

Este artículo forma parte de la guía: Superficies de identidad del navegador: panorama de coherencia

Lleva BotBrowser de la investigación a producción

Usa estas guías para entender el modelo y después avanzar hacia validación multiplataforma, contextos aislados y despliegue de navegador preparado para escalar.