Volver al Centro de conocimiento
Red

Encabezados HTTP personalizados en BotBrowser: indicador, perfil o CDP

Añade encabezados de solicitud propios de tu aplicación con --bot-custom-headers, el perfil o comandos CDP, y mantén coherentes User-Agent y Sec-CH-UA, que gestiona el perfil.

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.

Esta guía trata de añadir encabezados de solicitud propios de la aplicación sin tocar los que gestiona el perfil, como User-Agent y Sec-CH-UA. BotBrowser entrega a las solicitudes HTTP y HTTPS los encabezados que configuras; no puede decidir qué nombres acepta tu backend ni evitar que un servidor o una pasarela los rechace.

Resumen rápido

Deja en el perfil o en el indicador los valores estables y reserva los comandos CDP para los dinámicos; ningún nombre que gestione el perfil debe repetirse en el conjunto personalizado. Comprueba el mismo encabezado en la solicitud inicial, en el preflight CORS y tras una redirección.

Contenido de esta guía

Encabezados estándar y encabezados personalizados

Cada solicitud HTTP que envía un navegador lleva un conjunto de campos de encabezado. Algunos describen el propio navegador: User-Agent indica el navegador y su versión, Sec-CH-UA y sus equivalentes describen la marca y la plataforma de forma estructurada, y Accept-Language enumera las preferencias de idioma. Otros describen la aplicación: un token de autorización, un identificador de compilación, el nombre de un inquilino o una pista de enrutamiento que una pasarela lee antes de que la solicitud llegue a la aplicación. El primer grupo debe mantenerse coherente con la identidad de navegador que elegiste. El segundo lo defines tú por completo.

Diagrama: el indicador --bot-custom-headers, el campo configs.customHeaders del perfil y los comandos CDP de BotBrowser aportan encabezados de aplicación a la misma solicitud saliente, junto con los encabezados estándar que gestiona el perfil; la decisión final de autorizar la toma el servidor receptor.

Esa separación es la razón por la que los encabezados personalizados son una función aparte. Cuando se carga un perfil, BotBrowser mantiene los encabezados estándar que gestiona el perfil, como User-Agent y Sec-CH-UA, alineados con la identidad de navegador de ese perfil. Los encabezados personalizados se sitúan a su lado. Están pensados para valores propios de la aplicación. Un encabezado personalizado con el mismo nombre que uno existente puede sobrescribirlo, así que mantén fuera del conjunto personalizado los nombres que gestiona el perfil, como User-Agent y Sec-CH-UA. Si una página debe presentarse como un navegador concreto, un encabezado suelto que lo contradiga crea justo el tipo de incoherencia que luego cuesta explicar, así que la regla es sencilla: los encabezados estándar vienen del perfil y los de aplicación vienen de ti.

La semántica de los campos está definida en RFC 9110. Los nombres de campo no distinguen mayúsculas de minúsculas, de modo que X-App-Version y x-app-version nombran el mismo campo. El valor de un campo es una cadena y, cuando el mismo nombre aparece varias veces, el receptor puede tratar las líneas como una única lista separada por comas. Estos detalles importan en la práctica, porque un conjunto de encabezados que parece correcto en un objeto JSON puede interpretarse de otro modo en una pasarela que normaliza nombres, fusiona duplicados o rechaza caracteres poco habituales.

Los usos típicos de los encabezados personalizados se agrupan así:

  • Pistas de autenticación y autorización, como una clave de API o un token de portador que la pasarela espera en cada llamada.
  • Marcas de aplicación, como un número de compilación, un identificador de inquilino o el nombre de un indicador de función que el backend usa para enrutar.
  • Interruptores de pruebas y preproducción, como un encabezado que selecciona un despliegue canario o activa respuestas detalladas en un entorno de pruebas propio.
  • Convenciones de vistas web móviles, como un valor X-Requested-With que un sitio espera de un contenedor de aplicación.

Los encabezados personalizados no sirven para describir la ruta de red. Encabezados como X-Forwarded-For y X-Real-IP pertenecen a la infraestructura de proxies y balanceadores, y un servidor bien configurado no da peso a un valor fijado por quien opera el navegador. Establecerlos desde el navegador solo genera confusión, así que usa nombres propios de tu aplicación.

Los valores de los encabezados son responsabilidad de quien opera el navegador. Un encabezado que lleva una credencial debe tratarse como cualquier otro secreto: mantenlo fuera de los registros compartidos, rótalo según el calendario que defina tu backend y envíalo solo a los orígenes que deban recibirlo. BotBrowser envía los encabezados que configuras a las solicitudes HTTP y HTTPS, así que el alcance de lo que configuras es el alcance de lo que queda expuesto.

Elegir entre el indicador, la configuración del perfil y los comandos CDP

BotBrowser documenta tres formas de definir encabezados personalizados, y la adecuada depende de la frecuencia con que cambia el conjunto y de quién lo mantiene. Las tres requieren una licencia PRO.

La primera es el indicador de inicio --bot-custom-headers. Recibe un objeto JSON cuyas claves son nombres de encabezado y cuyos valores son cadenas. Es la opción más simple para un conjunto estático: los encabezados quedan fijados al arrancar el navegador, se aplican desde la primera solicitud y el comando de inicio es el único lugar donde leerlos. Encaja con una tarea programada, una ejecución de CI o un servicio que siempre llama al mismo backend con la misma marca de aplicación.

La segunda es el campo de perfil configs.customHeaders. Aquí los encabezados se guardan en la configuración del perfil en lugar de en el comando de inicio. Resulta útil cuando el conjunto pertenece al perfil y no a la ejecución, por ejemplo cuando un perfil representa siempre un mismo contenedor de aplicación y debe llevar la misma marca allí donde se use. Los encabezados viajan con el archivo de perfil, así que cualquier lanzador que lo cargue obtiene el mismo comportamiento sin argumentos adicionales.

La tercera son los comandos CDP de nivel navegador: BotBrowser.setCustomHeaders, BotBrowser.getCustomHeaders, BotBrowser.addCustomHeader, BotBrowser.removeCustomHeader y BotBrowser.clearCustomHeaders. Cambian el conjunto de encabezados mientras el navegador está en ejecución, sin reiniciarlo. La documentación presenta los comandos CDP como la más flexible de las tres vías, lo que los convierte en la opción natural para un token que rota durante una sesión o para un encabezado que debe cambiar entre dos navegaciones.

Una guía breve de decisión:

  • El conjunto no cambia durante una ejecución: usa el indicador.
  • El conjunto pertenece a un perfil concreto y debe viajar con él: usa configs.customHeaders.
  • El conjunto cambia mientras el navegador está abierto: usa los comandos CDP en la sesión de nivel navegador.
  • Distintos contextos de navegador necesitan conjuntos distintos: pasa el indicador mediante indicadores por contexto, como se muestra más adelante.

Los tres métodos pueden coexistir, por lo que conviene decidir de antemano cuál es responsable de cada encabezado. La documentación los enumera por prioridad: primero los comandos CDP, después el indicador de línea de comandos y por último el campo del perfil. Aun así, si un mismo nombre se define en dos sitios, conviene confirmar qué valor se envía antes de que un servidor se queje. Una convención práctica es dejar las marcas estables en el perfil o en el indicador y reservar los comandos CDP para los valores que de verdad son dinámicos.

Un matiz de vocabulario ayuda al leer la documentación. Un conjunto reemplazado con setCustomHeaders sustituye al conjunto personalizado anterior, no a los encabezados estándar que gestiona el perfil. addCustomHeader y removeCustomHeader afectan a una sola entrada personalizada, y clearCustomHeaders vacía el conjunto personalizado. No los uses para borrar ni reescribir User-Agent ni Sec-CH-UA; deja esos nombres al perfil.

Para las cookies, no uses ningún encabezado Cookie. BotBrowser tiene un indicador específico, --bot-cookies, con importación acotada por contexto, y esa es la vía compatible para el estado de las cookies. Tratar las cookies como un encabezado personalizado omitiría el ámbito y la caducidad que las cookies están diseñadas para tener.

Iniciar con un conjunto estático de encabezados

Para un conjunto estático, pasa el objeto JSON al indicador de inicio. En una shell, las comillas simples alrededor del valor mantienen intacto el JSON:

chrome --bot-profile="path/to/profile.enc" \
       --bot-custom-headers='{"X-App-Version":"2.1.0","X-Tenant":"acme-test"}'

Cuando inicias desde código, la regla de comillas cambia. Las comillas simples del ejemplo de shell existen solo para la shell. En JavaScript, el argumento llega directamente al proceso, así que el valor debe ser la cadena JSON sin más. Si añades comillas alrededor, pasan a formar parte del valor y el navegador recibe un texto que no es JSON válido.

const headers = { 'X-App-Version': '2.1.0', 'X-Tenant': 'acme-test' };

// Correcto: el argumento es el indicador, un signo igual y el texto JSON
args.push('--bot-custom-headers=' + JSON.stringify(headers));

// Incorrecto: las comillas simples pasan a formar parte del valor
args.push(`--bot-custom-headers='${JSON.stringify(headers)}'`);

Un inicio completo con Playwright queda así:

const { chromium } = require('playwright-core');

(async () => {
  const headers = { 'X-Auth': 'token123', 'X-Client': 'webapp' };

  const browser = await chromium.launch({
    executablePath: 'path/to/botbrowser/chrome',
    headless: true,
    args: ['--bot-profile=path/to/profile.enc', '--bot-custom-headers=' + JSON.stringify(headers)],
  });

  const page = await browser.newPage();
  await page.goto('https://example.com');
  await browser.close();
})();

La versión con Puppeteer solo cambia en la llamada de inicio:

const puppeteer = require('puppeteer-core');

(async () => {
  const headers = { 'X-Auth': 'token123' };

  const browser = await puppeteer.launch({
    executablePath: 'path/to/botbrowser/chrome',
    headless: true,
    args: ['--bot-profile=path/to/profile.enc', '--bot-custom-headers=' + JSON.stringify(headers)],
  });

  const page = await browser.newPage();
  await page.goto('https://example.com');
  await browser.close();
})();

Si prefieres guardar los encabezados con el perfil, pon el mismo objeto en configs.customHeaders dentro de la configuración del perfil. El valor es un objeto simple de pares de cadenas, igual que en el indicador, y el valor por defecto es un objeto vacío. Cuando existen un valor de perfil y un indicador a la vez, comprueba el resultado en un punto de eco antes de fiarte de uno u otro, como se explica en la sección de verificación.

Conviene resolver algunos detalles antes del primer inicio:

  • Usa solo valores de cadena. Los números y los booleanos deben escribirse como cadenas, porque los valores de encabezado son texto.
  • Limita los nombres a caracteres de token habituales. Muchos servidores y los intermediarios del camino rechazan espacios y signos de puntuación en un nombre.
  • Mantén el tamaño total razonable. La documentación no fija un límite concreto, pero cada encabezado se envía con cada solicitud, y los servidores y las pasarelas aplican sus propios límites al tamaño de los encabezados.
  • No incluyas secretos en un comando de inicio guardado en scripts compartidos o visible en listados de procesos. Léelos desde el entorno o desde un almacén de secretos en el momento del inicio.

En configuraciones al estilo de vista web de Android, la documentación muestra el mismo indicador para reproducir un valor X-Requested-With que enviaría un contenedor de aplicación. El patrón es idéntico: un único objeto JSON pasado mediante el indicador, aplicado a las solicitudes HTTP y HTTPS.

Cambiar encabezados en tiempo de ejecución y por contexto de navegador

Un indicador estático no basta cuando un valor cambia durante una sesión, por ejemplo un token de corta duración que se renueva, o un encabezado que debe diferir entre dos etapas de un flujo. Para eso BotBrowser ofrece comandos CDP. Deben enviarse a la sesión de nivel navegador, no a una sesión de nivel página.

Con Playwright, abre una sesión de nivel navegador y envía el comando:

const cdpSession = await browser.newBrowserCDPSession();

// Reemplaza todo el conjunto personalizado
await cdpSession.send('BotBrowser.setCustomHeaders', {
  headers: { 'X-Requested-With': 'com.example.app', 'X-Session': 'first' },
});

// Lee el conjunto personalizado actual
const current = await cdpSession.send('BotBrowser.getCustomHeaders');
console.log(current.headers);

// Añade o actualiza una entrada
await cdpSession.send('BotBrowser.addCustomHeader', {
  name: 'X-Session',
  value: 'refreshed',
});

// Elimina una entrada o vacía el conjunto personalizado
await cdpSession.send('BotBrowser.removeCustomHeader', { name: 'X-Session' });
await cdpSession.send('BotBrowser.clearCustomHeaders');

Con Puppeteer, la sesión de nivel navegador se obtiene del destino del navegador:

const cdpSession = await browser.target().createCDPSession();

await cdpSession.send('BotBrowser.setCustomHeaders', {
  headers: { 'X-Requested-With': 'com.example.app' },
});

await cdpSession.send('BotBrowser.addCustomHeader', {
  name: 'X-Token',
  value: 'my-token',
});

Si envías uno de estos comandos a una sesión de nivel página, la llamada falla con ProtocolError: 'BotBrowser.setCustomHeaders' wasn't found. Ese error suele indicar que la sesión se creó desde una página en lugar de desde el navegador. Cambia a la sesión de nivel navegador y el comando se encuentra.

Los cinco comandos cubren el ciclo de vida completo de un conjunto personalizado:

  • setCustomHeaders reemplaza todos los encabezados personalizados por el objeto que pasas.
  • getCustomHeaders devuelve el conjunto personalizado actual, útil para registrar aquello en lo que vas a apoyarte.
  • addCustomHeader añade o actualiza una entrada por nombre.
  • removeCustomHeader elimina una entrada por nombre.
  • clearCustomHeaders elimina todos los encabezados personalizados.

Un patrón fiable es aplicar el nuevo conjunto, iniciar después la navegación que depende de él y volver a leer el conjunto con getCustomHeaders cuando necesites estar seguro del estado actual.

A veces tareas distintas necesitan encabezados distintos en el mismo navegador. BotBrowser lo permite asignando encabezados por contexto de navegador. Los indicadores por contexto se pasan mediante BotBrowser.setBrowserContextFlags, y el indicador de encabezados personalizados es uno de los que un contexto puede llevar:

const client = await browser.target().createCDPSession();

const contextA = await browser.createBrowserContext();
await client.send('BotBrowser.setBrowserContextFlags', {
  browserContextId: contextA._contextId,
  botbrowserFlags: ['--bot-profile=path/to/profile.enc', '--bot-custom-headers={"X-Requested-With":"com.app.one"}'],
});

const contextB = await browser.createBrowserContext();
await client.send('BotBrowser.setBrowserContextFlags', {
  browserContextId: contextB._contextId,
  botbrowserFlags: ['--bot-profile=path/to/profile.enc', '--bot-custom-headers={"X-Requested-With":"com.app.two"}'],
});

Aquí cada contexto lleva su propio conjunto de encabezados, así que dos páginas abiertas a la vez envían marcas de aplicación distintas. Recuerda la misma regla de comillas: dentro del arreglo cada entrada es un argumento, de modo que el texto JSON se escribe sin comillas de shell adicionales.

Verificar los encabezados y gestionar el preflight de CORS

Verifica siempre una configuración de encabezados contra un punto que informe de lo que recibió. Un servicio de eco público como httpbin sirve para una comprobación rápida, y un punto de preproducción que controles es aún mejor, porque además muestra qué hace tu propia pasarela con los valores.

const page = await context.newPage();
await page.goto('https://httpbin.org/headers');
const headersText = await page.textContent('body');
console.log('Received headers:', headersText);

Una buena verificación tiene tres partes:

  • Confirma que cada encabezado personalizado que configuraste aparece en la respuesta, con el valor exacto que fijaste.
  • Confirma que User-Agent y Sec-CH-UA siguen coincidiendo con el perfil cargado, lo que demuestra que el conjunto estándar quedó intacto.
  • Abre el panel de red de las herramientas de desarrollo del navegador y comprueba que los encabezados aparecen en los distintos tipos de solicitud que hace la página, como el documento, los scripts, las imágenes y las llamadas fetch.

Si un encabezado no aparece, la causa suele ser una de tres. El JSON puede ser inválido, casi siempre por el error de comillas descrito antes. El comando puede haberse enviado a una sesión de nivel página en lugar de a la de nivel navegador. O un intermediario entre el navegador y el punto de eco puede haber eliminado o renombrado el campo, y por eso resulta valiosa la comparación directa con un servicio que controlas.

El segundo comportamiento que conviene entender es CORS. Un navegador trata una solicitud entre orígenes de forma distinta a una del mismo origen. En muchas solicitudes entre orígenes, el navegador envía primero una solicitud de preflight con el método OPTIONS. Lleva Access-Control-Request-Method y Access-Control-Request-Headers, que enumeran el método y los encabezados no incluidos en la lista segura que la solicitud real pretende usar. El servidor responde con Access-Control-Allow-Origin, Access-Control-Allow-Methods y Access-Control-Allow-Headers, y solo si la respuesta cubre la solicitud el navegador continúa. La guía de CORS de MDN describe el intercambio completo, incluido Access-Control-Max-Age, que permite al navegador reutilizar una respuesta de preflight durante un periodo.

Los encabezados no estándar son el desencadenante habitual. Un grupo reducido de encabezados, como Accept, Accept-Language y Content-Language, está en la lista segura y no provoca un preflight por sí solo. Un encabezado como X-Auth-Token o X-Tenant no está en ese grupo. Cuando el navegador añade un encabezado así a una solicitud entre orígenes, puede activarse un preflight. Si el servidor de destino no incluye el nombre del encabezado en Access-Control-Allow-Headers, la solicitud puede fallar. La documentación de BotBrowser lo dice igual: añadir encabezados no estándar puede provocar un preflight en algunos sitios, y el servidor de destino debe permitirlos.

Esto tiene varias consecuencias prácticas:

  • Si eres dueño del servidor de destino, añade los nombres de encabezado a su respuesta Access-Control-Allow-Headers y decide durante cuánto tiempo puede almacenarse una respuesta de preflight.
  • Si no eres dueño del servidor, no puedes cambiar cómo responde. Elige otro encabezado u otro enfoque, por ejemplo llevar el valor en un lugar que el servidor ya acepte.
  • Las solicitudes del mismo origen no necesitan preflight, así que una prueba contra tu propio origen puede pasar mientras el mismo encabezado falla contra otro origen. Prueba contra el origen que de verdad vas a usar.
  • Una respuesta de preflight que permite el encabezado no autoriza la solicitud. La autenticación y la autorización siguen siendo decisiones separadas del servidor.

El tamaño también importa. Servidores, pasarelas y CDN imponen límites al tamaño total de los encabezados de solicitud. Un conjunto grande de encabezados personalizados, o un valor demasiado largo, puede provocar un rechazo que nada tiene que ver con CORS ni con BotBrowser. Si las solicitudes empiezan a fallar después de que el conjunto crece, reduce el conjunto antes de buscar en otra parte.

Dónde encaja BotBrowser y dónde termina

BotBrowser admite añadir encabezados HTTP de solicitud personalizados mediante --bot-custom-headers, mediante el campo de perfil configs.customHeaders y mediante los comandos CDP de nivel navegador BotBrowser.*CustomHeaders. Los encabezados se aplican a las solicitudes HTTP y HTTPS y pueden asignarse por contexto de navegador, de modo que un equipo puede enviar un conjunto documentado de encabezados de aplicación mientras el perfil mantiene coherentes los encabezados estándar como User-Agent y Sec-CH-UA. El control de encabezados requiere una licencia PRO. BotBrowser no puede hacer que un servidor acepte, autorice o confíe en los encabezados añadidos, no puede omitir un preflight de CORS ni los límites de encabezados y de tamaño que aplica un servidor, y no sustituye tu propio diseño de encabezados y autenticación. El valor de un encabezado lo decide la aplicación que lo lee, así que el lado del servidor sigue siendo responsabilidad tuya.

En la práctica, esto significa tratar la función como un medio de transporte para un diseño de encabezados que ya has definido. Decide qué nombres espera tu backend, qué orígenes pueden recibirlos, cómo se emite y se rota un token y qué aspecto debe tener una solicitud rechazada. Después usa el indicador, el campo del perfil o los comandos CDP para entregar ese diseño desde el navegador. Si el diseño es sólido, la entrega es sencilla. Si el diseño no está claro, ninguna elección de indicador lo arreglará.

Conviene tener presentes algunos límites:

  • Usa los encabezados personalizados para añadir valores de la aplicación. No sobrescribas User-Agent ni Sec-CH-UA; el perfil ya controla esos campos.
  • Los encabezados de infraestructura de proxy, como X-Forwarded-For, quedan fuera de lo que recomienda esta guía, porque describen una ruta de red que el navegador no controla.
  • Las cookies pertenecen al indicador de cookies, no a un encabezado Cookie personalizado.
  • Cada encabezado que añades es visible para el servidor al que se envía y para cualquier intermediario del camino, así que trata el conjunto como público para esas partes.

Para la configuración relacionada, la guía de configuración de proxy explica cómo se establece el enrutamiento de red, User-Agent y Client Hints explica cómo los encabezados de identidad estándar siguen al perfil, y navegador multicuenta trata de mantener separados los contextos cuando cada uno necesita su propio conjunto de encabezados.

Comprobación reproducible de encabezados

La siguiente ejecución usa un fixture HTTP de loopback para que la observación pueda repetirse sin enviar credenciales ni datos de prueba a un servicio de terceros. El fixture expone /echo, devuelve un 302 desde /redirect y responde a OPTIONS con la lista solicitada. El comando es deliberadamente más pequeño que un inicio del navegador: comprueba el protocolo y el diagnóstico de fallos, mientras que el indicador de BotBrowser y las llamadas CDP siguen siendo los mecanismos de entrega descritos arriba.

echo custom=custom-http-headers-20261017 ua=fixture-UA/1.0 sec=\"Fixture\";v=\"1\"
redirect status=200 custom=custom-http-headers-20261017
preflight status=204 allow=x-test-run

La primera línea demuestra que el valor de aplicación, el campo user-agent y el campo con forma de client hints llegaron juntos al receptor controlado. La segunda importa porque una redirección puede cambiar el origen o hacer que el navegador y el servidor eliminen un encabezado; este fixture conservó el valor personalizado al seguir una redirección en el mismo host. La tercera línea es una respuesta del servidor, no un permiso del navegador: allow=x-test-run indica que el receptor incluyó ese nombre en la lista del preflight, pero no autentica la solicitud final.

Usa la salida como un árbol de diagnóstico. Si falta custom en la línea de eco, revisa las comillas JSON y el alcance del indicador. Si el eco funciona pero una solicitud entre orígenes se detiene antes de llegar a la aplicación, revisa Access-Control-Allow-Headers y la política de origen. Si la primera solicitud funciona pero cambia la línea de redirección, compara el destino, los indicadores del contexto y cualquier pasarela que reescriba campos. El fixture registra User-Agent y el valor con forma de Sec-CH-UA para mostrar qué recibió el servidor; no es una puntuación de detector ni afirma que Node.js sea el motor BotBrowser. El archivo de evidencia guarda los resúmenes del binario Node y del perfil estable para repetir la misma comprobación de protocolo local.

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

La página de referencia documenta las opciones. La comparación añadida comprueba un valor del perfil, uno de inicio y uno de CDP por contexto en la solicitud inicial, el preflight CORS y una redirección. Un fallo en un solo salto apunta al alcance o a la política del servidor.

Fuentes

Referencias públicas usadas para las afirmaciones sobre encabezados, CORS y BotBrowser:

Conclusión práctica

Decide de antemano qué método es dueño de cada encabezado y no repitas nombres que gestiona el perfil. Si el valor llega en la solicitud inicial pero falla en el preflight o en la redirección, el problema está en el alcance o en la política del servidor, no en el navegador.

#cabeceras HTTP#Custom-Headers#red#privacidad#Request

Este artículo forma parte de la guía: Panorama de configuración de proxy: mapa de decisiones de red

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.