Automatizar perfiles de navegador con una API local

Inicia un perfil desde un script, recibe un endpoint de depuración y conecta Playwright o Puppeteer a un navegador que ya trae su identidad y su proxy.
Automatizar un navegador antidetect suele presentarse como un problema difícil. No lo es, siempre que la herramienta te entregue lo único que tu biblioteca de automatización ya sabe usar: un endpoint de depuración.
La forma que tiene
PowerOps ejecuta una API HTTP enlazada a la dirección de loopback. Tu script le pide que inicie un perfil; ella lanza el navegador con la identidad, el almacenamiento y el proxy de ese perfil ya aplicados, y devuelve el endpoint WebSocket del navegador en ejecución. Tu script se conecta a ese endpoint con Playwright, Puppeteer o cualquier otra cosa que hable el protocolo DevTools.
La biblioteca de automatización nunca tiene que saber qué es una huella digital. Cuando se conecta, el entorno ya está establecido.
Iniciar un perfil
curl -s -H "Authorization: Bearer $POWEROPS_API_KEY" \
http://127.0.0.1:50326/status
Todas las rutas, salvo la comprobación de estado, exigen una clave bearer. Iniciar un navegador devuelve el endpoint al que conectarse:
curl -s -X POST \
-H "Authorization: Bearer $POWEROPS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"profileId": "..."}' \
http://127.0.0.1:50326/browser/start
Conectar tu biblioteca
import { chromium } from "playwright";
const res = await fetch("http://127.0.0.1:50326/browser/start", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.POWEROPS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ profileId }),
});
const { ws } = await res.json();
// The profile's identity, storage and proxy are already in place.
const browser = await chromium.connectOverCDP(ws);
const [context] = browser.contexts();
const page = context.pages()[0] ?? await context.newPage();
await page.goto("https://example.com");
La línea importante es el comentario. En tu script no hay ninguna configuración de huella digital, porque configurar el entorno no es trabajo de tu script. Pertenece al perfil, y se mantiene igual tanto si el perfil lo abre una persona haciendo clic en una fila como si lo abre una tarea programada a las tres de la madrugada.
Qué cubre la API
- La ruta de estado es una comprobación de salud, y la única que no necesita clave.
- Las rutas de navegador inician, detienen y consultan los navegadores en ejecución.
- Las rutas de perfil crean, actualizan, consultan y eliminan perfiles.
- Las rutas de proxy gestionan la biblioteca de proxies y asignan rutas.
- Las rutas de grupo organizan perfiles en bloque.
- Las rutas de extensión importan y asignan extensiones.
Cómo se mantiene en local
Una API que maneja navegadores con cuentas iniciadas merece unas palabras sobre sus límites.
- Se enlaza a 127.0.0.1. No hay ningún ajuste que la haga escuchar en otra interfaz.
- Se exige una clave bearer en todas las rutas salvo la comprobación de estado.
- Valida la cabecera Host y no envía cabeceras CORS, de modo que una página web abierta en tu navegador habitual no puede alcanzarla.
- Los secretos son de solo escritura: las contraseñas de perfil, los secretos de doble factor y las contraseñas de proxy nunca los devuelve una ruta de consulta.
Un patrón que vale la pena copiar
Consulta los perfiles de un grupo, inicia cada uno, haz el trabajo y deténlo. Ejecútalos de pocos en pocos y no todos a la vez. El límite es la memoria de tu propio equipo, ya que cada perfil es un proceso de navegador real.
const { profiles } = await api("/profiles?groupId=" + groupId);
for (const batch of chunk(profiles, 5)) {
await Promise.all(batch.map(async (profile) => {
const { ws } = await api("/browser/start", { profileId: profile.id });
try {
await doTheWork(ws);
} finally {
await api("/browser/stop", { profileId: profile.id });
}
}));
}
Detener el perfil en un `finally` importa más de lo que parece: cerrarlo limpiamente es lo que escribe el estado del navegador, y un perfil terminado a la fuerza a mitad de sesión puede perder la sesión que acababa de establecer.
