Conocimiento

Cómo usar proxies residenciales en Puppeteer (incluido page.authenticate)

Proxies en Puppeteer: el proxy va en los args de lanzamiento, las credenciales en page.authenticate, rotación geo por página a través de un gateway, y bloqueo de recursos.

Chris Collins

Chris Collins

5 de agosto de 2026 · 8 min de lectura

Puppeteer maneja un Chromium real, que es exactamente lo que quieres cuando un destino renderiza su contenido con JavaScript, esconde datos tras interacción, o hace fingerprint de cualquier cosa que no sea un navegador real. Añadir un proxy residencial son un par de líneas, pero Puppeteer parte el trabajo entre dos lugares distintos de un modo que hace tropezar a casi todos la primera vez: la dirección del proxy va en los argumentos de lanzamiento, y las credenciales van en otro sitio por completo.

Esta es la entrada de Puppeteer junto a proxies residenciales con Playwright; si quieres clientes HTTP simples en lugar de un navegador completo, mira proxies en Node.js. Aquí nos centramos en las trampas propias del navegador.

Todo lo de abajo usa el gateway residencial de Shifter: un endpoint, p.shifter.io:443, con todo el targeting codificado en el nombre de usuario. Cambia el host y las credenciales por otro proveedor; la forma es la misma.

El modelo del gateway en un párrafo

El nombre de usuario del proxy lleva tu autenticación y tu targeting. No cambias de endpoint para cambiar de país o de sesión, cambias la cadena del nombre de usuario:

customer-USERNAME-country-us-sid-abc123-ttl-600

country-us apunta a Estados Unidos, sid fija una sesión sticky, ttl mantiene esa IP durante N segundos. Omite sid/ttl y cada conexión nueva rota. La contraseña se mantiene constante. En Puppeteer, el host va en un flag de lanzamiento y ese nombre de usuario va en page.authenticate.

El montaje: proxy en args de lanzamiento, credenciales en page.authenticate

Chromium toma el servidor proxy como un flag de línea de comandos, --proxy-server, pasado por los args de Puppeteer. No aceptará user:pass@host ahí, Chromium no lee credenciales de ese flag. En su lugar las proporcionas por página con page.authenticate, que responde al desafío 407 del proxy con el Proxy-Authorization correcto.

import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({
headless: true,
args: ['--proxy-server=http://p.shifter.io:443'], // solo host, sin credenciales
});
const page = await browser.newPage();
await page.authenticate({
username: `${process.env.SHIFTER_USER}-country-us`, // el targeting vive aquí
password: process.env.SHIFTER_PASS,
});
await page.goto('https://api.ipify.org');
console.log(await page.evaluate(() => document.body.innerText)); // una IP residencial de EE. UU.
await browser.close();

Dos cosas que interiorizar. El nombre de usuario incluye los flags de targeting (-country-us), porque la geo vive ahí, no en la URL. Y page.authenticate no es opcional para un proxy autenticado, sin él cada navegación muere en un 407. Esta partición, host en el flag y credenciales en page.authenticate, es el error de proxy en Puppeteer más común.

Rotar geo y sesiones a través de un gateway

Aquí está la consecuencia útil de ese diseño. El host del proxy se fija al lanzar el navegador y no puedes cambiarlo por página, pero no lo necesitas. Como el targeting vive en el nombre de usuario y page.authenticate se pone por página, darle a cada página un nombre de usuario distinto la enruta a través de una identidad distinta en el mismo gateway. Un navegador, muchas geos, sin relanzar.

async function pageFor(browser, country, sid) {
const page = await browser.newPage();
const user = `${process.env.SHIFTER_USER}-country-${country}`
+ (sid ? `-sid-${sid}-ttl-600` : '');
await page.authenticate({ username: user, password: process.env.SHIFTER_PASS });
return page;
}
const de = await pageFor(browser, 'de', 'job-42'); // sesión sticky alemana
const us = await pageFor(browser, 'us', null); // US rotativo

Dale a cada unidad lógica de trabajo su propio sid y rota entre unidades, no a mitad de sesión (sticky vs rotativo cubre la distinción), y mapea el trabajo a identidades como describe el post sobre reparto de carga. Para aislar cookies y almacenamiento entre identidades, pon cada una en su propio contexto de navegador:

const context = await browser.createBrowserContext(); // cookies/almacenamiento aislados
const page = await context.newPage();
await page.authenticate({ username: userFor('gb'), password: pass });

Ojo al nombre: Puppeteer reciente lo llama createBrowserContext(), las versiones antiguas lo llamaban createIncognitoBrowserContext(). Misma idea, renombrada.

Trampa 1: reutiliza el navegador, nunca lances uno por petición

Lanzar Chromium es pesado, un navegador fresco por petición paga cientos de milisegundos de arranque más memoria real cada vez, la sobrecarga que la guía de latencia existe para eliminar. Lanza un navegador al arrancar y reutilízalo, abriendo páginas o contextos para trabajo concurrente y cerrándolos al terminar. Un pool de páginas bajo un navegador de larga vida es la forma correcta.

Trampa 2: bloquea los recursos que no necesitas

Un navegador obtiene todo lo que uno real obtiene: imágenes, fuentes, media, hojas de estilo, analítica. Si solo quieres el HTML o unos campos, eso es ancho de banda que pagas y tiempo que esperas. Puppeteer te deja interceptar peticiones y abortar las que no necesitas, lo que recorta sustancialmente tanto tu tiempo de carga como tu factura de ancho de banda.

await page.setRequestInterception(true);
page.on('request', (req) => {
const blocked = ['image', 'font', 'media', 'stylesheet'];
if (blocked.includes(req.resourceType())) req.abort();
else req.continue();
});

Sé selectivo: algunos sitios no renderizarán el contenido que quieres sin su CSS o un script específico, así que bloquea con agresividad, luego confirma que los datos siguen apareciendo. Cuando lo hacen, esta es la aceleración más barata disponible en un navegador headless.

Trampa 3: el navegador es solo la mitad de no ser bloqueado

Una IP residencial maneja la mitad de red de parecer humano, pero Puppeteer sigue manejando Chromium headless, y los sitios hacen fingerprint del navegador también, navigator.webdriver, rarezas específicas de headless, y señales de automatización. Una IP limpia con buena reputación te mantiene fuera de muchos desafíos, pero no disfraza un navegador obviamente automatizado. Usa un Puppeteer y Chromium actuales para tener el modo headless moderno en lugar del viejo, fácilmente detectable, mantén el viewport y el user-agent realistas, y maneja la página a ritmo humano. Los errores que disparan la detección aplican a la capa del navegador tanto como a la capa de IP, y las dos tienen que cuadrar.

Trampa 4: acota tu concurrencia

Cada página abierta es una pestaña de navegador real que retiene memoria real, así que no puedes abrir miles como dispararías peticiones HTTP. Mantén un pool acotado de páginas o contextos y reutilízalos, y limita el trabajo en vuelo por host de destino para que un sitio frágil no reciba una paliza mientras uno permisivo pasa hambre. Más paralelismo más allá de la tolerancia de un destino compra bloqueos y caídas por falta de memoria, no throughput (cómo evitar que te bloqueen).

Verifica que de verdad estás en el proxy

Antes de hacer benchmark o depurar cualquier otra cosa, confirma la IP de salida desde dentro de la página:

await page.goto('http://ip-api.com/json');
console.log(await page.evaluate(() => document.body.innerText)); // espera el país objetivo

Tu propia IP significa que el flag --proxy-server no se aplicó. Un cuelgue en un diálogo 407 significa que falta page.authenticate o las credenciales están mal. Un cuelgue general significa que la salida local está bloqueada. Los tres se cubren en la guía de diagnóstico de timeouts.

Preguntas frecuentes

¿Por qué no funciona poner user:pass@host en --proxy-server? Chromium no lee las credenciales del proxy del flag --proxy-server. Pasa solo el host ahí y proporciona las credenciales con page.authenticate({ username, password }), que maneja el desafío 407 del proxy. Como el gateway codifica el targeting en el nombre de usuario, el nombre de usuario completo (con -country-...) va en page.authenticate.

¿Cómo uso un país distinto por página si el proxy se fija al lanzar? No cambias el host del proxy, cambias el nombre de usuario de page.authenticate. Como el targeting vive en el nombre de usuario y el host del gateway es constante, cada página puede autenticarse con un nombre de usuario distinto y salir por una identidad distinta. Un navegador sirve muchas geos.

¿Puedo rotar el proxy sin relanzar el navegador? Sí, para identidad y geo, variando el nombre de usuario de page.authenticate por página o contexto. Solo relanzarías si necesitaras un host de proxy genuinamente distinto, lo que no ocurre con un único endpoint de gateway.

¿Cómo recorto ancho de banda en Puppeteer? Activa la intercepción de peticiones y aborta los tipos de recurso que no necesitas (imágenes, fuentes, media, a menudo hojas de estilo). Confirma que el destino sigue renderizando los datos que quieres, luego mantén los bloqueos. Es la mayor palanca única sobre velocidad y coste en un navegador headless.

¿Puppeteer o Playwright? Ambos manejan navegadores reales y ambos funcionan bien con proxies residenciales. Playwright toma el proxy (con credenciales) directamente en sus opciones de contexto; Puppeteer lo parte en el flag de lanzamiento más page.authenticate. Elige según encaje de ecosistema y código existente; los conceptos del proxy son los mismos.

En resumen

Puppeteer más proxies residenciales es directo en cuanto la partición encaja: el host del proxy va en --proxy-server al lanzar, y las credenciales, llevando tu targeting en el nombre de usuario, van en page.authenticate por página. Rota geo y sesiones variando ese nombre de usuario en lugar de relanzar, aísla identidades con contextos de navegador, reutiliza un navegador de larga vida, bloquea los recursos que no necesitas, y recuerda que el fingerprint del navegador tiene que parecer tan humano como la IP.

Hazlo bien y Puppeteer maneja los destinos cargados de JavaScript que los clientes HTTP simples no pueden. Apúntalo al gateway residencial, y recuerda que la calidad del pool decide con qué frecuencia te desafían siquiera (reputación de IP). La página de precios tiene los planes por GB para probarlo contra tus propios destinos.

¿Listo para empezar?

Prueba los proxies residenciales de Shifter, más de 205M IPs, más de 195 países, desde 0,75 $/GB.

Comenzar