Aislamiento de perfiles por tarea para agentes
Asigna un perfil por tarea de agente, demuestra la separación del almacenamiento y entiende los límites de la identidad de red compartida.
BotBrowser Team
Quieres la documentación estructurada de Identidad?
Este artículo forma parte de la biblioteca editorial. Para pasos de configuración, material de referencia y actualizaciones continuas, entra en la sección de docs.
Un agente que gestiona varias tareas necesita una asignación explícita de perfil antes de iniciar cada navegador. BotBrowser admite un perfil proporcionado por el operador al iniciar y expone la página resultante, pero no puede asignar tareas, no elige el perfil y no garantiza cómo un detector clasifica una sesión. El operador es responsable de asociar cada taskId con un profileId.
TL;DR
- Crea la relación tarea-perfil antes del inicio; un reintento no debe heredar silenciosamente el perfil de la tarea anterior.
- Da a cada perfil su propia partición de almacenamiento y una política de red aprobada. Un perfil compartido puede llevar cookies, almacenamiento local, permisos y la misma ruta configurada a la siguiente tarea.
- Usa el accesorio ejecutable para demostrar la separación con dos directorios persistentes y luego ejecuta la variante defectuosa con un directorio compartido.
- Un accesorio correcto demuestra lo que la página puede leer. No demuestra el veredicto de un detector, el proceso que inició el navegador ni el cumplimiento de los límites de una plataforma externa.
Contenido
- Por qué el bucle del agente necesita un límite de perfil
- Asignar el perfil antes de iniciar
- Ejecutar un accesorio de separación de almacenamiento
- Comprobar la identidad de red como superficie separada
- Cerrar, reintentar y auditar cada asignación
- Interpretación y límites
- Conclusión práctica
Por qué el bucle del agente necesita un límite de perfil
Un bucle de agente convierte un flujo de navegador en una secuencia de trabajos con alcance independiente. La tarea A puede autenticarse en un tenant de prueba autorizado, mientras que la tarea B debe comenzar sin ningún estado de ese tenant. Si ambos inicios apuntan a un perfil persistente, la segunda tarea puede heredar cookies, almacenamiento local, permisos, caché y otro estado antes de su primera acción.
Playwright describe un BrowserContext como una sesión aislada con sus propias cookies y almacenamiento. Ese límite es útil, pero no equivale a elegir un perfil BotBrowser. Un perfil es una entrada de lanzamiento y puede transportar configuración que va más allá del almacenamiento de página. La guía de gestión de perfiles cubre propiedad, versiones, retención y ciclo de vida; los planificadores de agentes aplican estas prácticas al asignar perfiles a tareas.
El artículo más cercano sobre aislamiento de navegadores multi-cuenta se centra en flujos humanos que mantienen separadas las cuentas. Un bucle de agente añade la asignación: cada tarea, reintento y reinicio del worker debe recibir un perfil deliberado. La guía de navegador headless para agentes de IA cubre el traspaso entre agente y navegador y la evidencia del proceso, pero no establece la separación de identidad entre dos ejecuciones.
Asignar el perfil antes de iniciar
Mantén un registro de asignación pequeño que el lanzador pueda validar sin abrir el paquete protegido. Debe contener identificador de tarea, identificador de perfil, directorio de almacenamiento, referencia de política de red, responsable y estado:
{
"taskId": "tenant-a-checkout-042",
"profileId": "profile-us-east-07",
"storageDir": "/var/lib/agent-sessions/profile-us-east-07",
"networkPolicyRef": "egress-us-east-07",
"state": "approved"
}
Resuelve este registro antes de llamar a chromium.launchPersistentContext() o al lanzador BotBrowser equivalente. Rechaza una asignación ausente, retirada o ya alquilada. Un reintento debe referirse a su propio evento de asignación, no reutilizar el directorio que el worker dejó disponible.
Con Playwright, un contexto persistente da a un proceso de navegador un directorio de datos. En un inicio BotBrowser, el operador también proporciona el argumento de perfil y las opciones de red aprobadas. Mantén esos valores juntos en el registro y escribe solo identificadores estables, nunca contenido del perfil ni secretos de proxy.
La asignación de perfil es un control operativo, no una promesa sobre la decisión de un sitio. Hace que el límite previsto sea revisable. No vuelve permisibles dos cuentas no relacionadas, no permite ignorar un límite de plataforma ni garantiza que un tercero acepte la sesión.
Ejecutar un accesorio de separación de almacenamiento
El siguiente accesorio de Node.js usa Chromium incluido en Playwright y un servidor HTTP local. Escribe una cookie y un valor de localStorage inocuos en la tarea A, lee los valores en la tarea B y muestra si la segunda tarea los heredó. La primera ejecución da un directorio distinto a cada tarea; la segunda reutiliza deliberadamente un directorio para mostrar la fuga.
// save as profile-isolation-fixture.mjs
import { chromium } from 'playwright';
import { createServer } from 'node:http';
import { mkdtemp, rm } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
const server = createServer((request, response) => {
response.setHeader('Content-Type', 'text/html');
response.end('<!doctype html><title>profile fixture</title><p data-fixture="profile-isolation">owned fixture</p>');
});
await new Promise(resolve => server.listen(0, '127.0.0.1', resolve));
const port = server.address().port;
const origin = `http://127.0.0.1:${port}`;
async function runTask(taskId, storageDir, writeState) {
const context = await chromium.launchPersistentContext(storageDir, { headless: true });
const page = await context.newPage();
await page.goto(origin);
if (writeState) {
await page.context().addCookies([{ name: 'task_marker', value: taskId, url: origin }]);
await page.evaluate(value => localStorage.setItem('task_marker', value), taskId);
}
const observed = {
cookie: (await context.cookies()).find(cookie => cookie.name === 'task_marker')?.value ?? null,
localStorage: await page.evaluate(() => localStorage.getItem('task_marker')),
};
await context.close();
return observed;
}
const root = await mkdtemp(join(tmpdir(), 'agent-profile-fixture-'));
const separateA = await runTask('task-a', join(root, 'profile-a'), true);
const separateB = await runTask('task-b', join(root, 'profile-b'), false);
console.log(JSON.stringify({ case: 'separate', taskA: separateA, taskB: separateB }));
const sharedA = await runTask('task-a', join(root, 'shared-profile'), true);
const sharedB = await runTask('task-b', join(root, 'shared-profile'), false);
console.log(JSON.stringify({ case: 'shared', taskA: sharedA, taskB: sharedB }));
await rm(root, { recursive: true, force: true });
server.close();
Ejecuta node profile-isolation-fixture.mjs. La forma esperada es:
{"case":"separate","taskA":{"cookie":"task-a","localStorage":"task-a"},"taskB":{"cookie":null,"localStorage":null}}
{"case":"shared","taskA":{"cookie":"task-a","localStorage":"task-a"},"taskB":{"cookie":"task-a","localStorage":"task-a"}}
El caso separado establece un límite visible para la página: la tarea B no puede leer el marcador de la tarea A. El caso compartido es el accesorio de fallo; ambos valores prueban que la segunda ejecución abrió el mismo almacenamiento persistente. Es un ejemplo ejecutable localmente, no una observación de una ejecución de BotBrowser.
El accesorio usa de forma deliberada un origen local y datos sintéticos. No registra credenciales, visita servicios externos ni afirma que una página pueda inspeccionar cada ajuste del navegador. Para una comprobación de producción, conserva la misma comparación, usa un endpoint de solo lectura aprobado y guarda el ID de asignación junto al resultado.
Qué comprueba y qué omite el accesorio
El objetivo es hacer visible una fuga con valores sin significado comercial. La cookie pertenece al origen local y localStorage lo escribe la propia página. Como ambos valores se leen después de un inicio nuevo, un resultado no nulo en la tarea B se atribuye al directorio persistente y no a una variable del proceso Node.js. La limpieza elimina los directorios temporales para que la siguiente ejecución empiece conocida.
No prueba caché, registros de service worker, permisos, IndexedDB, descargas ni extensiones. Esas superficies pueden importar en una carga real y deben añadirse a un accesorio aprobado separado cuando formen parte del límite de identidad. Añade un marcador con nombre cada vez, registra el valor vacío esperado para una tarea nueva y mantén el accesorio en solo lectura respecto de cualquier servicio externo.
El accesorio tampoco selecciona un perfil BotBrowser. Un lanzador de producción puede envolver la misma función de tarea con un argumento --bot-profile resuelto y un directorio asignado. Mantén el envoltorio fuera del código de página para no confundir la observación con una prueba de la línea de comandos. La configuración de Playwright de BotBrowser documenta la integración; la selección y asignación del paquete siguen siendo responsabilidad del operador.
Hacer que el resultado esperado sea comprobable
No dependas de que una persona examine dos líneas JSON. El planificador puede fallar si una tarea nueva ve un marcador, o si el caso compartido no lo ve:
function requireValue(value, expected, label) {
if (value !== expected) throw new Error(`${label}: expected ${expected}, got ${value}`);
}
requireValue(separateB.cookie, null, 'separate cookie');
requireValue(separateB.localStorage, null, 'separate localStorage');
requireValue(sharedB.cookie, 'task-a', 'shared cookie');
requireValue(sharedB.localStorage, 'task-a', 'shared localStorage');
Mantén esta aserción junto al resultado, no en un control de salud genérico. Un control que solo confirma que cargó una página puede pasar mientras está conectado el almacenamiento equivocado. Ante un fallo, incluye taskId, profileId, la etiqueta de la ruta de almacenamiento, la versión del navegador y el resultado del accesorio en el registro restringido. Nunca pongas cookies reales ni credenciales de proxy en un registro compartido.
Comprobar la identidad de red como superficie separada
Separar el almacenamiento no separa automáticamente la identidad de red. Asocia cada perfil con una política de red y una región aprobadas, y verifica la ruta mediante un endpoint controlado por el operador que informe de la dirección pública y la región de la petición. Registra el resultado junto a profileId; no lo deduzcas de las cookies ni de una carga correcta.
Si el operador asigna la misma referencia de política de red a dos tareas, ambas usan el proxy y la ruta configurados; reutilizar un perfil no demuestra por sí solo que compartan la ruta. La guía de configuración de proxy de BotBrowser documenta las entradas independientes de inicio y encaminamiento. Es una comprobación de configuración, no un veredicto de detector. Un directorio de almacenamiento diferente no convierte una ruta configurada en dos rutas.
Mantén las comprobaciones independientes:
| Superficie | Comprobación | Qué establece | Qué no establece por sí sola |
|---|---|---|---|
| Almacenamiento | Cookie task_marker y localStorage | El estado visible para la página está separado | El ejecutable, el paquete de perfil o la IP pública |
| Red | Endpoint de eco del operador | La petición usó la ruta registrada en ese momento | La clasificación de un tercero o la estabilidad futura |
| Inicio | Comando redactado y registro de asignación | El operador proporcionó la entrada de perfil prevista | Que todas las señales de la página coincidan |
La documentación de huella por contexto de BotBrowser describe entradas de identidad acotadas al contexto, y la documentación de gestión cubre ciclo de vida y propiedad. Usa esas referencias para definir la asignación aprobada. La guía de navegador headless para agentes de IA explica por qué el resultado de página y la evidencia del proceso deben permanecer separados; aplica la misma distinción a la red.
La respuesta del endpoint debe llevar hora y referencia de asignación. La dirección pública y la región pueden cambiar tras una rotación, un cambio de infraestructura o una política actualizada. Trátala como una medición de esa petición, no como una propiedad permanente del perfil. Si una tarea necesita región estable, el planificador debe rechazar una ruta fuera de la política antes de abrir la página y cerrar la sesión si la ruta deja de estar disponible.
No sustituyas la comprobación de ruta por una conjetura del navegador. navigator.language, una zona horaria o un resultado de permiso de geolocalización describen ajustes del navegador; ninguno identifica por sí solo el camino público. Un endpoint controlado por la misma organización puede asociar la respuesta con la asignación sin pedir a un tercero que clasifique la sesión. Mantén la respuesta mínima, redacta los informes amplios y conserva el registro completo solo el tiempo aprobado.
Cerrar, reintentar y auditar cada asignación
El aislamiento depende tanto del ciclo de vida como del comando de inicio. Cierra una tarea en este orden: deja de aceptar trabajo, permite que la página llegue a un estado controlado, recoge el resultado, cierra el contexto y marca el destino del almacenamiento. Solo entonces el planificador debe alquilar el worker a otra tarea. Un proceso que todavía escribe cookies al reasignar el directorio puede crear una fuga que parece aleatoria.
Usa un evento de asignación inmutable para cada intento. Un reintento recibe un evento nuevo con una razón como navigation-timeout, fixture-mismatch o route-unavailable. Conserva el evento anterior enlazado con su resultado en lugar de sobrescribir su profileId. Así se puede decidir si el fallo pertenece a la aplicación, al lanzador o al paquete.
El planificador puede aplicar comprobaciones de cierre seguro:
| Comprobación antes de iniciar | Rechazar cuando | Motivo |
|---|---|---|
| Estado del perfil | Falta, está retired o no está aprobado | Impide trabajo con una identidad no revisada |
| Reserva de almacenamiento | El directorio está activo para otra asignación | Evita escrituras concurrentes y estado cruzado |
| Política de red | Falta o queda fuera de la región | Mantiene explícita la propiedad de la ruta |
| Pareja del navegador | La versión no coincide con el registro aprobado | Evita un paquete y versión no revisados |
| Cierre anterior | El propietario anterior no cerró limpiamente | Impide reutilizar un directorio sucio |
Cuando una comprobación rechaza el inicio, devuelve una razón corta a la cola y el detalle al canal restringido. “La reserva de almacenamiento está activa” es accionable; volcar el paquete o la línea completa de comandos en un registro compartido no lo es. La gestión de perfiles describe estados de propiedad y retirada que hacen auditables estas comprobaciones.
Durante la revisión compara tres registros: evento de asignación, resultado visible del accesorio y evidencia de inicio o ruta del operador. Deben coincidir en tarea y ventana temporal, pero responden preguntas distintas. Una cookie igual no prueba una ruta igual; una ruta igual no prueba que se abrió el perfil previsto; un comando igual no prueba que se cargó el origen esperado.
Para un worker de larga duración, programa un reinicio limpio en un límite definido por la política en lugar de mantener una asignación indefinidamente. El reinicio no sustituye la separación, pero puede revelar problemas de cierre ocultos en un solo proceso. Registra si era esperado, qué perfil se liberó y si la siguiente tarea recibió un directorio nuevo o uno persistente aún aprobado.
Este registro también ayuda en un incidente. Si un tenant ve el banner de una tarea anterior, compara primero los eventos y las etiquetas de almacenamiento y luego revisa el resultado del accesorio del worker afectado. Si solo un worker muestra el marcador, aísla su directorio y detén nuevas tareas mientras el responsable revisa el cierre. Si todos lo muestran, revisa el mapeo del planificador y el volumen compartido antes de cambiar código de página.
Interpretación y límites
Interpreta una comparación limpia como un resultado de aceptación limitado. Indica que este accesorio, en esta máquina, observó los valores de almacenamiento esperados y, si se comprobó por separado, que un endpoint del operador devolvió el resultado registrado. No indica que un sitio acepte la sesión, que un navegador sea indistinguible de otro ni que un detector dé un veredicto concreto.
Investiga un fallo en la capa responsable. Un marcador no nulo en el caso separado apunta al directorio, al cierre o a la asignación. Un cambio de red apunta a la política, al proxy o a la interpretación del endpoint. Un lanzador diferente es evidencia de proceso y no se corrige pidiendo al agente que inspeccione JavaScript.
No uses perfiles por tarea para ignorar límites de cuentas o condiciones de una plataforma. El aislamiento sirve para tenants autorizados, casos de prueba y límites de privacidad. El operador sigue siendo responsable de credenciales, consentimiento, retención, límites de velocidad y reglas del servicio.
Preguntas frecuentes
¿Basta un BrowserContext de Playwright para dos tareas?
Solo si los contextos se crean y cierran bajo una política explícita. Un contexto puede separar cookies y almacenamiento, pero no reemplaza la decisión sobre el perfil BotBrowser, la política de red y el responsable de cada tarea.
¿El accesorio demuestra que se iniciaron dos perfiles BotBrowser?
No. Solo demuestra los valores de almacenamiento que la página local pudo leer. Confirma el ejecutable, el argumento de perfil redactado y el registro de asignación con la evidencia del proceso del operador.
¿Los perfiles separados garantizan un resultado de detector?
No. La separación elimina una clase de estado compartido accidental. Los sitios combinan muchas señales y cambian sus reglas; pueden clasificar una sesión por motivos ajenos al accesorio.
¿Qué hace un reintento después de un fallo?
Cierra el contexto antiguo, conserva su ID y resultado, y obtiene una nueva asignación aprobada según la política. No heredes el directorio que quedó en el worker solo porque está disponible.
Fuentes
- API BrowserType de Playwright
- Contextos de navegador de Playwright
- Configuración de Playwright de BotBrowser
- Gestión de perfiles de BotBrowser
- Huella por contexto de BotBrowser
- Configuración de proxy de BotBrowser
Conclusión práctica
Asigna profileId, almacenamiento y política de red antes de iniciar cada tarea del agente. Demuestra el límite con dos directorios y el fallo deliberado del directorio compartido, y verifica la red mediante un endpoint controlado por el operador. Mantén separadas las observaciones de página, la evidencia de inicio y la clasificación de terceros. Así la separación de perfiles por tarea queda revisable sin prometer un veredicto de detector ni ignorar reglas de ninguna plataforma.
Este artículo forma parte de la guía: Superficies de identidad del navegador: panorama de coherencia
Artículos Relacionados
Configurar browser-use con un navegador controlado
IdentidadAislamiento multicuenta del navegador: ajustes independientes
IdentidadVarias cuentas de redes sociales con aislamiento del navegador
Primeros pasosNavegadores headless para agentes de IA
Primeros pasosGestión coherente de perfiles de navegador
IdentidadPartición del almacenamiento del navegador y privacidad
Ejecuta la misma comprobación en BotBrowser
Carga un perfil, mantén dentro del navegador las señales que acabas de leer y confirma el resultado en tu propia máquina antes del despliegue.