Conhecimento

Como Usar Proxies Residenciais com Playwright

Um guia prático sobre proxies residenciais no Playwright: autenticação, rotação por contexto, geo-targeting, redução de consumo de banda e as pegadinhas do Chromium.

Chris Collins

Chris Collins

6 de julho de 2026 · 11 min de leitura

Conectar um proxy residencial ao Playwright é questão de poucas linhas assim que você vê como é feito. A dificuldade nunca está na opção de launch, e sim nos detalhes que ninguém escreve: como as credenciais codificam o targeting, a pegadinha do Chromium que quebra proxies por contexto, como a rotação se mapeia em contextos de navegador, e o fato de que toda imagem que o navegador carrega é banda que você paga.

Este é o complemento de como usar proxies residenciais com Python, para o lado do navegador. Exemplos prontos para copiar e colar que realmente funcionam, além das partes que transformam um snippet funcional em automação que sobrevive em produção.

Tudo abaixo usa o gateway residencial da Shifter: um único endpoint, p.shifter.io:443, com todo o targeting codificado no nome de usuário. Se você usa outro provedor, a estrutura é a mesma; basta trocar o host e o formato de credenciais. Os exemplos são em Node/JavaScript; um snippet de Playwright em Python está perto do final.

A primeira coisa que você precisa entender

Em um gateway residencial, o nome de usuário do proxy carrega sua autenticação e seu targeting. Você não muda de endpoint para trocar de país ou sessão, você muda a string do nome de usuário. Um nome de usuário se parece com isto:

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

Leia da esquerda para a direita: id da conta, depois flags. country-us direciona para os EUA. sid-abc123 fixa uma sessão sticky. ttl-600 mantém esse IP por 600 segundos. Remova sid/ttl e toda nova conexão gira para um novo IP. A senha é constante. Esse é todo o modelo mental, o resto é encaixar isso no slot de proxy do Playwright.

Mantenha as credenciais em variáveis de ambiente, nunca fixas no código:

const USER = process.env.SHIFTER_USER; // your account username
const PASS = process.env.SHIFTER_PASS;
const GATEWAY = "http://p.shifter.io:443";

Uma observação específica do Playwright, logo de início: não coloque o nome de usuário e a senha embutidos na URL do proxy. O Chromium ignora credenciais de proxy embutidas, então http://user:pass@host falha silenciosamente na autenticação. O Playwright tem campos dedicados username e password no objeto proxy, use-os.

A versão de 10 linhas

Para um único proxy em todo o navegador, defina proxy em launch():

const { chromium } = require("playwright");
const USER = process.env.SHIFTER_USER;
const PASS = process.env.SHIFTER_PASS;
(async () => {
const browser = await chromium.launch({
proxy: {
server: "http://p.shifter.io:443",
username: `${USER}-country-us`, // targeting lives here
password: PASS,
},
});
const page = await browser.newPage();
await page.goto("https://api.ipify.org?format=json");
console.log(await page.textContent("body")); // {"ip":"<a US residential IP>"}
await browser.close();
})();

O campo username é onde reside todo o modelo do gateway. ${USER}-country-us direciona para os EUA; adicione sid/ttl para um IP sticky, adicione city/asn para restringir ainda mais. A senha nunca muda.

A pegadinha do Chromium: proxies por contexto

A versão de proxy único é boa para uma identidade. Mas o verdadeiro motivo para usar o Playwright é rodar muitas identidades, e para isso você quer um proxy diferente por contexto de navegador (cada contexto tem seus próprios cookies/armazenamento isolados, ou seja, seu próprio “usuário”).

Aqui está a armadilha: no Chromium, proxies por contexto só funcionam se você iniciar o navegador com um proxy já definido. Se você iniciar sem proxy, todo newContext({ proxy }) é ignorado silenciosamente. A solução é um servidor placeholder no launch:

const browser = await chromium.launch({
proxy: { server: "per-context" }, // placeholder, enables per-context proxying
});
// Now each context can carry its own real proxy + targeting
const ctxUS = await browser.newContext({
proxy: {
server: "http://p.shifter.io:443",
username: `${USER}-country-us-sid-a1-ttl-600`,
password: PASS,
},
});
const ctxDE = await browser.newContext({
proxy: {
server: "http://p.shifter.io:443",
username: `${USER}-country-de-sid-b2-ttl-600`,
password: PASS,
},
});

ctxUS navega em um IP dos EUA, ctxDE em um IP alemão, ao mesmo tempo, em um único navegador. Este é o padrão sobre o qual construir. (Firefox e WebKit não precisam estritamente do placeholder, mas defini-lo é inofensivo e mantém seu código compatível entre navegadores.)

Rotativo vs sticky, à moda do Playwright

Em um scraper HTTP puro, você costuma rotacionar a cada requisição. Em um navegador, isso geralmente está errado: um usuário real não muda de IP no meio da sessão, então um IP que muda entre carregamentos de página enquanto os cookies permanecem constantes é um sinal de detecção. O mapeamento idiomático é:

  • Um contexto = uma identidade sticky. Dê a cada contexto um sid único e um ttl que cubra a sessão, para que todos os carregamentos de página compartilhem um IP, como um usuário real.
  • Rotacione criando novos contextos. Um contexto novo com um sid novo (ou sem sid) recebe um novo IP. Feche o antigo quando terminar.
async function contextForSession(browser, sessionId, country = "us") {
return browser.newContext({
proxy: {
server: "http://p.shifter.io:443",
username: `${USER}-country-${country}-sid-${sessionId}-ttl-600`,
password: PASS,
},
});
}
// Process 50 targets, each with its own IP-stable identity
for (let i = 0; i < 50; i++) {
const ctx = await contextForSession(browser, `job-${i}`, "us");
const page = await ctx.newPage();
await page.goto("https://example.com/item/" + i);
// ... scrape ...
await ctx.close(); // done with this identity
}

Escolha o sid você mesmo, qualquer string única por sessão lógica. A mesma string retorna o mesmo IP até o TTL expirar. Execute contextos de forma concorrente (um pequeno pool) em vez de todos os 50 ao mesmo tempo; mais navegadores não é mais velocidade, e uma rajada de IPs martelando um único alvo ainda dispara a detecção comportamental. Se você está sendo bloqueado consistentemente em vez de intermitentemente, o problema é qualidade de IP ou comportamento, não rotação, veja como evitar ser bloqueado ao fazer scraping.

Geo-targeting, e alinhando o navegador ao IP

Como o targeting reside no nome de usuário, a geolocalização é apenas uma flag: country-de, adicione city-berlin ou asn-3320 para restringir. Mas com um navegador real há uma segunda metade que as pessoas perdem: sua fingerprint de navegador precisa concordar com seu IP. Um IP residencial alemão combinado com um locale en-US e um fuso horário de Nova York é uma contradição que sistemas anti-bot sinalizam de imediato. (Veja por que scrapers são bloqueados.)

O Playwright permite alinhar tudo isso no contexto:

const ctx = await browser.newContext({
proxy: {
server: "http://p.shifter.io:443",
username: `${USER}-country-de-city-berlin-sid-de1-ttl-600`,
password: PASS,
},
locale: "de-DE",
timezoneId: "Europe/Berlin",
geolocation: { latitude: 52.52, longitude: 13.405 },
permissions: ["geolocation"],
});

Nomes de cidades usam o formato do gateway (minúsculas); combine flags livremente, a ordem não importa para o gateway. Alinhar locale/timezoneId/geolocation ao país do proxy é uma das ações de maior impacto para parecer um usuário local genuíno.

Reduza sua banda (você paga por GB)

Este ponto é específico de navegadores e importa, porque proxies residenciais são cobrados por gigabyte. Um navegador headless, deixado sozinho, baixa toda imagem, fonte, vídeo e script de rastreamento da página, a maioria dos quais você não precisa para scraping. Abortá-los pode cortar a banda (e o custo) em bem mais da metade, e acelera suas execuções.

Use context.route() para bloquear tipos de recursos pesados antes que cheguem ao proxy:

await ctx.route("**/*", (route) => {
const type = route.request().resourceType();
if (["image", "media", "font"].includes(type)) {
return route.abort(); // never downloaded, never billed
}
return route.continue();
});

Mantenha document, script, xhr e fetch (os dados reais e o JS que os renderiza); descarte o resto. Se o site carrega conteúdo de forma lazy atrás de imagens, teste se seu scraping ainda funciona, mas para a maioria dos trabalhos isso é dinheiro de graça. Combina bem com o modelo por GB abordado em proxies residenciais precificados por banda.

Verificando se realmente funciona

Antes de confiar em uma configuração, confirme duas coisas: o IP está no país certo (geo) e ele muda entre contextos (rotação). Uma verificação rápida:

const page = await ctx.newPage();
await page.goto("http://ip-api.com/json");
const data = JSON.parse(await page.textContent("body"));
console.log(data.query, data.countryCode); // expect a DE IP

Crie dois contextos com sids diferentes e você deve ver dois IPs diferentes, ambos no país correto. Se o país estiver errado, verifique a ortografia da sua flag. Se o IP nunca mudar entre contextos, você provavelmente esqueceu o placeholder no momento do launch e o Chromium está ignorando o proxy por contexto.

Os erros que realmente acontecem

O Playwright expõe problemas de proxy como erros de navegação, não códigos de status HTTP. Os três que você vai encontrar:

  • net::ERR_TUNNEL_CONNECTION_FAILED autenticação do proxy falhou, ou uma flag não reconhecida (um erro de digitação em country ou asn, ou credenciais embutidas que o Chromium ignorou). Corrija os campos username/password; tentar de novo não vai ajudar.
  • net::ERR_PROXY_CONNECTION_FAILED não foi possível alcançar o gateway, ou nenhum IP correspondeu a um filtro excessivamente restrito (como country + city + asn). Verifique a conectividade, depois relaxe uma flag.
  • Uma página que carrega mas mostra um bloqueio/CAPTCHA o alvo, não o proxy, está recusando você. Rotacione para um novo contexto/IP, diminua o ritmo e alinhe a fingerprint como acima.

Envolva a navegação em um pequeno retry que cria um contexto novo em caso de falha:

async function gotoWithRetry(browser, url, country = "us", tries = 3) {
for (let attempt = 0; attempt < tries; attempt++) {
const ctx = await contextForSession(browser, `r-${Date.now()}-${attempt}`, country);
const page = await ctx.newPage();
try {
await page.goto(url, { waitUntil: "domcontentloaded", timeout: 30000 });
return { ctx, page }; // caller closes ctx when done
} catch (e) {
await ctx.close();
if (attempt === tries - 1) throw e;
await new Promise((r) => setTimeout(r, 2 ** attempt * 1000)); // 1s, 2s
}
}
}

Um contexto novo significa um IP novo, então um retry realmente obtém uma rota diferente, não a mesma que falhou.

Uma nota sobre SOCKS5

O gateway fala SOCKS5, mas há uma limitação do Playwright que vale conhecer: o Playwright/Chromium não suporta proxies SOCKS autenticados. Como o gateway autentica pelo nome de usuário (é ali que seu targeting reside), o SOCKS5 não é prático aqui, use o proxy HTTP mostrado acima, que é o padrão certo para scraping com navegador de qualquer forma. As vantagens e desvantagens do SOCKS estão em proxies SOCKS5 para automação.

O mesmo em Python

A API Python do Playwright espelha a versão JavaScript; o objeto proxy é idêntico:

from playwright.sync_api import sync_playwright
import os
USER, PASS = os.environ["SHIFTER_USER"], os.environ["SHIFTER_PASS"]
with sync_playwright() as p:
browser = p.chromium.launch(proxy={"server": "per-context"})
ctx = browser.new_context(proxy={
"server": "http://p.shifter.io:443",
"username": f"{USER}-country-us-sid-a1-ttl-600",
"password": PASS,
})
page = ctx.new_page()
page.goto("https://api.ipify.org")
print(page.text_content("body"))
browser.close()

Mesma regra do placeholder no launch, mesmo targeting codificado no nome de usuário. Para trabalho HTTP fora do navegador, o guia de Python cobre requests, httpx e Scrapy.

Perguntas frequentes

Por que http://user:pass@host não funciona no Playwright? O Chromium ignora credenciais de proxy embutidas. Coloque o nome de usuário e a senha nos campos dedicados username/password do objeto proxy. Este é o motivo mais comum de “o proxy não está funcionando” no Playwright.

Por que meus proxies por contexto são ignorados? Porque você iniciou o Chromium sem proxy. O proxy por contexto só é ativado se o navegador foi iniciado com um, passe um placeholder proxy: { server: "per-context" } para launch(), depois defina proxies reais em cada contexto.

Devo rotacionar o IP a cada requisição em um navegador? Não. Uma sessão de navegador deve manter um IP, como um usuário real. Use um sid sticky por contexto e rotacione criando novos contextos, não trocando de IP no meio da sessão.

Como executo diferentes países ao mesmo tempo? Um navegador, múltiplos contextos, cada um com um country-<cc> diferente em seu nome de usuário de proxy. Eles rodam de forma concorrente e independente.

Isso funciona com Puppeteer ou Selenium também? O gateway funciona. O Puppeteer recebe --proxy-server no launch e autentica via page.authenticate(); o Selenium usa uma capability de proxy ou uma extensão para autenticação. O targeting codificado no nome de usuário é idêntico; só a conexão muda. O modelo por contexto do Playwright é o mais limpo para trabalho com múltiplas identidades.

Minhas execuções estão consumindo banda rapidamente. O que fazer? Bloqueie imagens, mídia e fontes com context.route() como mostrado acima. Navegadores baixam tudo por padrão, e em um plano por GB isso é dinheiro real. Abortar recursos pesados costuma cortar o uso em mais da metade.

Encerrando

O padrão: inicie o Chromium com um placeholder per-context, dê a cada contexto um proxy cujo username codifica country/sid/ttl, alinhe locale/timezone/geolocation ao país, e aborte imagens e fontes para economizar banda. Rotacione criando novos contextos, não trocando de IP. Erros aparecem como falhas de navegação net::, e um retry que constrói um contexto novo garante um IP novo.

Comece pelos snippets acima, aponte-os para o gateway residencial, e você terá uma automação de navegador pronta para produção em uma tarde. Planos e taxas por GB estão na página de preços, e a referência completa de flags está na documentação do gateway.

Pronto para começar?

Experimente os proxies residenciais da Shifter, mais de 205M IPs, mais de 195 países, a partir de $0,75/GB.

Começar