---
title: "Playwright Timeout 30000ms Exceeded: como resolver o erro"
description: "Playwright timeout 30000ms exceeded indica que uma navegação, um locator, um expect ou o teste inteiro ficou sem tempo. Leia o call log e corrija a causa."
url: https://proxynet.io/pt-br/blog/playwright-timeout
date: 2026-10-05
author: "Acar Diveroli"
category: "Tutoriais, Web scraping"
lang: pt-BR
---

# Playwright Timeout 30000ms Exceeded: como resolver o erro

A sua verificação de preços funciona no seu notebook. Você a leva para um servidor, passa o tráfego por um proxy e, depois de meio minuto, o log mostra `TimeoutError: page.goto: Timeout 30000ms exceeded.` Na execução seguinte a página abre, e o script para uma linha depois com `locator.click: Timeout 30000ms exceeded.` Você muda o número para 60000, e agora o script falha depois de um minuto inteiro, porque o número nunca foi o problema.

Este guia cobre os quatro tipos de timeout, o call log, o `waitUntil`, onde definir os limites, proxies lentos e páginas de bloqueio que acabam virando "elemento não encontrado"; depois vêm um script de novas tentativas testado em Python e Node.js e o equivalente no Puppeteer. Todas as mensagens abaixo saíram das nossas execuções com Playwright 1.63 e Puppeteer 25.12 contra um site de teste local e um proxy de teste.

> **Nota: Resposta rápida**
>
> "Timeout 30000ms exceeded" significa que o Playwright esperou 30 segundos, o seu padrão, por algo que não aconteceu. As primeiras palavras dizem o quê: `page.goto` esperava a página carregar, `locator.click` esperava um elemento existir e aceitar o clique, `expect(...)` esperava uma condição (5 segundos por padrão), e `Test timeout of 30000ms exceeded` é o limite do Playwright Test para um teste inteiro. Leia o fim do call log e corrija a causa: navegue com `domcontentloaded` e espere o elemento de que você precisa, corrija o seletor ou a camada sobreposta, confira o status da resposta antes de esperar o conteúdo e defina os limites a partir de tempos de carregamento medidos.

## O que significa "Timeout 30000ms exceeded" no Playwright?

O Playwright espera sozinho: `page.goto()` até a página atingir um estado de carregamento, e cada ação de locator até o elemento existir e poder receber a ação. Quando uma espera chega ao limite, o Playwright lança um `TimeoutError`. Na biblioteca, esse limite é de 30.000 ms, ou seja, 30 segundos; as nossas execuções em Python e em Node.js pararam exatamente em 30,0 segundos.

A mensagem traz o método que esperou, o limite e, em um call log, o que o Playwright estava fazendo. Esta veio de uma página de teste cujo servidor nunca respondeu:

```text
TimeoutError: page.goto: Timeout 30000ms exceeded.
Call log:
  - navigating to "http://127.0.0.1:8090/slow", waiting until "load"
```

O Python escreve `Page.goto` e `Locator.click` com inicial maiúscula; o Node.js, `page.goto` e `locator.click`. Em Python, importe a classe com outro nome, porque o `TimeoutError` de `playwright.sync_api` esconderia o `TimeoutError` nativo do Python. No Node.js, é `errors.TimeoutError` do pacote `playwright`.

## Qual timeout se esgotou? Os quatro tipos

A biblioteca, que é o que os scrapers usam, dá 30 segundos a cada navegação e a cada ação. O executor de testes Playwright Test não lhes dá um limite próprio e, em vez disso, dá 30 segundos ao teste inteiro, como lista a [documentação de timeouts do Playwright](https://playwright.dev/docs/test-timeouts); é por isso que a referência da API JavaScript indica 0 como padrão do `goto`.

| A mensagem começa com | Tipo | Padrão | Como mudar |
|---|---|---|---|
| `page.goto: Timeout …` | Navegação | 30 s (biblioteca), nenhum (Test) | `timeout` na chamada, `set_default_navigation_timeout()`, `navigationTimeout` |
| `locator.click: Timeout …` | Ação ou locator | 30 s (biblioteca), nenhum (Test) | `timeout` na chamada, `set_default_timeout()`, `actionTimeout` |
| `expect(locator)… failed` com `Timeout: 5000ms` | Asserção | 5 s | `expect: { timeout }`, em Python `expect.set_options(timeout=…)` |
| `Test timeout of 30000ms exceeded.` | Teste inteiro (Playwright Test) | 30 s | `timeout` na configuração, `test.setTimeout()`, `test.slow()` |

Dois detalhes das nossas execuções. Em Python, um `expect()` que falha lança um `AssertionError` comum, que `except PlaywrightTimeoutError` não captura. E, quando o timeout do teste estoura durante o `page.goto`, o Playwright Test acrescenta `page.goto: net::ERR_ABORTED; maybe frame was detached?` abaixo da linha do timeout. Não é um erro de rede: o executor fechou a página enquanto a chamada ainda esperava.

## Como ler o call log?

O call log, o registro de chamadas que aparece abaixo da linha do erro, é a parte mais útil da mensagem. Aqui está um clique em um botão coberto por um aviso de cookies, resumido da nossa execução:

```text
Locator.click: Timeout 5000ms exceeded.
Call log:
  - waiting for locator("#buy")
    - locator resolved to <button id="buy">Add to cart</button>
  - attempting click action
    2 × waiting for element to be visible, enabled and stable
      - element is visible, enabled and stable
      - scrolling into view if needed
      - done scrolling
      - <div id="cookie-banner">We use cookies</div> intercepts pointer events
    - retrying click action
```

Leia em quatro passos:

1. **O método na primeira linha** diz qual foi a espera: `goto`, `click`, `fill`, `textContent`.
2. **O último passo do log** mostra onde parou. `waiting for locator("#price")` sem nada embaixo significa que nada correspondeu; `locator resolved to …` significa que o elemento foi encontrado, mas a ação não pôde ser executada.
3. **A linha do motivo**, se houver: `intercepts pointer events` (algo está por cima), `element is not visible`, `element is not enabled`.
4. **O tempo decorrido.** Uma falha exatamente no seu limite é uma espera real. Um erro anterior, como `net::ERR_PROXY_CONNECTION_FAILED`, é outro problema, tratado em [O que é Playwright e como usá-lo com proxy](/pt-br/blog/playwright-proxy).

## Timeouts de navegação: page.goto e waitUntil

O `page.goto()` espera um evento do ciclo de vida, escolhido com `waitUntil` (`wait_until` em Python):

- **`commit`**: a resposta chegou e o documento começou a carregar.
- **`domcontentloaded`**: o HTML foi analisado; imagens, fontes e iframes ainda podem estar carregando.
- **`load`** (o padrão): a página e os recursos que ela puxa, incluindo imagens e folhas de estilo, terminaram de carregar.
- **`networkidle`**: nenhuma conexão de rede por pelo menos 500 ms. A [referência do page.goto](https://playwright.dev/docs/api/class-page#page-goto) o marca como desaconselhado (discouraged) e recomenda confiar nas asserções.

O `load` padrão causa muitos timeouts de navegação: uma imagem lenta, um pixel de rastreamento ou um widget impede o evento de disparar enquanto o texto que você quer já está na página. Na nossa página de teste, o preço estava no HTML e uma imagem nunca terminava de carregar. Com `load`, o `goto` estourou o timeout após 10 segundos; com `domcontentloaded`, retornou em 0,1 segundo com o preço legível. O `networkidle` falhou em uma página que chama um endpoint a cada 300 ms, como fazem widgets de chat e preços ao vivo.

O padrão que se sustenta: navegue com `domcontentloaded` e depois espere o elemento específico de que você precisa.

```python
response = page.goto(url, wait_until="domcontentloaded")
price = page.locator("#price").inner_text()  # espera o elemento, no máximo até o timeout de ação
```

```js
const response = await page.goto(url, { waitUntil: "domcontentloaded" });
const price = await page.locator("#price").innerText();
```

Se o `goto` ainda estourar o timeout com `domcontentloaded`, o próprio HTML chegou tarde demais, e isso é uma questão de rede (veja a seção sobre proxies). Se os dados estão no HTML ou em um endpoint JSON, talvez você nem precise de um navegador; [Páginas estáticas e dinâmicas no web scraping](/pt-br/blog/static-vs-dynamic-pages) mostra como verificar.

## Timeouts de locator e de ação: a espera automática e o que a bloqueia

Antes de um clique, o Playwright verifica se o elemento está visível, estável (sem se mover) e habilitado e se ele realmente recebe o clique naquele ponto, e repete as verificações até o limite acabar. Um timeout de locator se resume a uma lista curta de causas:

- **O seletor não corresponde a nada.** Um erro de digitação, um nome de classe que muda a cada build ou um texto que varia conforme o idioma. Atributos estáveis (`id`, `data-*`) ou `get_by_role()` duram mais.
- **O elemento aparece tarde demais.** Um preço renderizado 12 segundos depois do carregamento falha sempre com um limite de 10 segundos.
- **Algo o cobre.** Avisos de cookies e janelas modais aparecem como `intercepts pointer events`. Feche a camada sobreposta como um visitante faria; `force=True` pula a verificação, e o clique cai onde nenhum usuário conseguiria clicar.
- **Ele está dentro de um iframe.** `page.locator("#price")` não olha dentro de frames; no nosso teste, ele estourou o timeout, enquanto `page.frame_locator("iframe").locator("#price")` devolveu o preço na hora.
- **Você está em uma página diferente da que imagina.** Uma página de bloqueio ou uma tela de login não tem `#price` (veja abaixo).

O `page.wait_for_selector()` ainda funciona, mas a referência da API do Playwright o marca como desaconselhado e prefere os locators, que buscam o elemento de novo a cada tentativa e por isso sobrevivem a uma nova renderização. Como isso difere das esperas explícitas do Selenium está em [Playwright ou Selenium: qual escolher no seu projeto?](/pt-br/blog/playwright-vs-selenium).

## Definir timeouts de propósito: por chamada, por contexto, na configuração

Um `timeout` passado a uma chamada vale mais do que qualquer outro. Abaixo dele, os padrões da página valem mais do que os do contexto, e um padrão de navegação vale mais do que o geral. Em Python, defina os padrões no contexto para que todas as páginas dele os herdem:

```python
context = browser.new_context()
context.set_default_navigation_timeout(15_000)  # goto, reload, wait_for_url
context.set_default_timeout(10_000)             # locators, cliques, esperas
page = context.new_page()
page.goto(slow_report_url, timeout=45_000)      # uma página sabidamente lenta ganha mais
```

No Playwright Test, os limites ficam na configuração. Com esta configuração, na nossa execução um elemento ausente falhou com `locator.click: Timeout 10000ms exceeded.` e uma página que nunca respondeu, com `page.goto: Timeout 15000ms exceeded.`:

```js
import { defineConfig } from "@playwright/test";

export default defineConfig({
  timeout: 60_000,              // o teste inteiro, incluindo hooks e fixtures
  expect: { timeout: 10_000 },  // cada asserção expect(...)
  use: {
    actionTimeout: 10_000,      // click, fill, textContent ...
    navigationTimeout: 15_000,  // goto, reload, waitForURL ...
  },
});
```

`test.slow()` triplica o limite de um teste lento. Evite `timeout=0` em produção: uma página que nunca responde passa a segurar um contexto para sempre. Limites de dois minutos em toda parte não são muito melhores; uma fila com cem URLs mortas passa a levar mais de três horas.

## Proxies lentos: meça primeiro, depois defina o timeout

Um proxy acrescenta um salto a cada requisição, e um navegador faz muitas requisições por página. IPs residenciais passam por conexões domésticas e costumam acrescentar mais latência do que os de datacenter, então um limite que nunca dispara na linha do seu escritório pode disparar por um IP de saída distante. Meça antes de escolher um número. Este script abre a mesma página cinco vezes em contextos novos, com o limite desligado só durante a medição:

```python
import statistics
import time

from playwright.sync_api import sync_playwright

PROXY = {"server": "http://pr.proxynet.io:8000", "username": "user", "password": "pass"}
URL = "https://shop.example.com/product/42"

with sync_playwright() as p:
    browser = p.chromium.launch(proxy=PROXY)
    times = []
    for _ in range(5):
        context = browser.new_context()  # sessão nova, sem cache entre as execuções
        page = context.new_page()
        start = time.monotonic()
        page.goto(URL, wait_until="domcontentloaded", timeout=0)  # sem limite durante a medição
        page.locator("#price").wait_for(timeout=0)
        times.append(time.monotonic() - start)
        context.close()
    browser.close()

print("runs:", " ".join(f"{t:.2f}s" for t in times))
print(f"median {statistics.median(times):.2f}s, slowest {max(times):.2f}s")
```

Pelo nosso proxy local de teste, que acrescenta 2 segundos a cada requisição, ele imprimiu:

```text
runs: 3.42s 3.38s 3.37s 3.38s 3.38s
median 3.38s, slowest 3.42s
```

Baseie o limite na execução mais lenta, com folga acima dela; nós escolhemos 15 segundos. Em um alvo real, colete mais amostras e meça de novo quando o país, o tipo de proxy ou o site mudarem. Mais três pontos:

- **Carregue menos.** Bloquear imagens, mídia e fontes com `page.route()` reduz as requisições por página; o código está no nosso guia de Playwright com proxy.
- **Escolha a saída conforme o trabalho.** Os IPs de saída dos [Proxies de datacenter](https://proxynet.io/pt-br/datacenter-proxy) são mais rápidos quando o alvo aceita IPs de datacenter. Quando um site exige IPs domésticos ou uma cidade, use os [Proxies residenciais](https://proxynet.io/pt-br/residential-proxy), com um limite próprio medido.
- **Confira as credenciais.** Com uma senha de proxy errada em um site HTTPS, o nosso listener de `requestfailed` imprimiu `net::ERR_TUNNEL_CONNECTION_FAILED` na hora, mas o `page.goto` só falhou quando o seu limite de 10 segundos acabou. Um problema de credenciais pode parecer um proxy lento, então acrescente este listener enquanto depura:

```python
page.on("requestfailed", lambda r: print("FAILED:", r.url, r.failure))
```

Fora do navegador, o Requests do Python relata falhas de proxy como "Max retries exceeded"; [Max Retries Exceeded With URL: o que é e como resolver](/pt-br/blog/max-retries-exceeded-with-url) explica como ler essa mensagem.

## Quando uma página de bloqueio vira "elemento não encontrado"

Este é o caso que mais custa tempo. O site recusa a requisição e serve uma página de bloqueio com status `403` ou `429`. O `page.goto()` não lança exceção para status de erro HTTP; o nosso `goto` retornou normalmente com um `403`. Em seguida, o script espera o limite inteiro por um elemento que a página de bloqueio nunca vai conter. O log fala em timeout; a resposta real era uma recusa.

A nossa página de bloqueio de teste tinha o título "Access denied", e o erro do `expect()` em Python chegou a imprimir o snapshot de acessibilidade dela, com `heading "Access denied"` dentro. Olhe antes de esperar:

1. Guarde a resposta que o `goto` retorna e leia o status dela.
2. Leia `page.title()`; páginas de bloqueio e de desafio têm títulos próprios.
3. Se qualquer um dos dois indicar bloqueio, pare: sem nova tentativa e sem esperar o elemento.
4. Descubra o motivo: o seu ritmo de requisições, o `robots.txt` e os termos do site, ou se ele oferece uma API.

Tentar de novo em uma página de bloqueio piora a situação, e trocar de IP para passar por cima de uma recusa não é solução: o site disse não. Um `429` significa requisições demais; diminua o ritmo e respeite o `Retry-After` ([429 Too Many Requests: o que é o erro de rate limit](/pt-br/blog/http-429-too-many-requests)). Por que os sites sinalizam visitantes automatizados está em [Como funciona a detecção de bots: a lógica anti-bot](/pt-br/blog/how-bot-detection-works). Não tratamos de formas de contornar essas páginas; o que dura é uma varredura mais lenta, uma permissão ou a API oficial ([Web scraping vs. API: qual você deve usar?](/pt-br/blog/web-scraping-vs-api)).

## Exemplo completo: timeouts medidos, verificação de bloqueio e novas tentativas

O script abre páginas de produto por um proxy. Cada tentativa recebe um contexto novo com limites definidos de propósito. Ele confere o status e o título antes de esperar o conteúdo, para diante de uma página de bloqueio e só tenta de novo nos timeouts, com uma espera que cresce de forma exponencial (exponential backoff) mais um componente aleatório (jitter), para que workers em paralelo não repitam as tentativas no mesmo compasso.

```python
"""Abre páginas de produto por um proxy com timeouts medidos, verificação de bloqueio e novas tentativas."""
import random
import time

from playwright.sync_api import TimeoutError as PlaywrightTimeoutError
from playwright.sync_api import sync_playwright

PROXY = {"server": "http://pr.proxynet.io:8000", "username": "user", "password": "pass"}
URLS = [f"https://shop.example.com/product/{n}" for n in (42, 43, 44)]

NAV_TIMEOUT = 15_000     # ms: cerca de 4x a página mais lenta que medimos pelo proxy
ACTION_TIMEOUT = 10_000  # ms: locators, cliques e esperas
ATTEMPTS = 3
STOP_STATUS = {403, 429}  # uma recusa ou um rate limit: tentar de novo só piora
STOP_WORDS = ("access denied", "blocked", "captcha", "verify you are human")  # ajuste para cada site

class Blocked(Exception):
    """O site respondeu com uma página de bloqueio ou de rate limit: pare e descubra o motivo."""

def fetch_price(browser, url):
    for attempt in range(1, ATTEMPTS + 1):
        context = browser.new_context()  # cookies e cache limpos a cada tentativa
        context.set_default_navigation_timeout(NAV_TIMEOUT)
        context.set_default_timeout(ACTION_TIMEOUT)
        page = context.new_page()
        start = time.monotonic()
        try:
            response = page.goto(url, wait_until="domcontentloaded")
            status = response.status if response else None
            title = page.title()
            if status in STOP_STATUS or any(word in title.lower() for word in STOP_WORDS):
                raise Blocked(f"HTTP {status}, title {title!r}")
            return page.locator("#price").inner_text()  # espera automaticamente até ACTION_TIMEOUT
        except PlaywrightTimeoutError as exc:
            print(f"  attempt {attempt}: {str(exc).splitlines()[0]} ({time.monotonic() - start:.1f}s)")
            if attempt == ATTEMPTS:
                raise
            time.sleep(2**attempt + random.random())  # 2-3 s, depois 4-5 s
        finally:
            context.close()

with sync_playwright() as p:
    browser = p.chromium.launch(proxy=PROXY)
    for url in URLS:
        print(url)
        try:
            print("  price:", fetch_price(browser, url))
        except Blocked as exc:
            print("  stopped, not retrying:", exc)
        except PlaywrightTimeoutError:
            print(f"  gave up after {ATTEMPTS} attempts")
    browser.close()
```

Executamos o script com o host trocado pelo nosso site de teste local (`shop.test`), pelo proxy que acrescenta 2 segundos por requisição; a terceira página foi configurada para travar nas duas primeiras requisições:

```text
http://shop.test/product/42
  price: $19.90
http://shop.test/product/43
  stopped, not retrying: HTTP 403, title 'Access denied'
http://shop.test/product/44
  attempt 1: Page.goto: Timeout 15000ms exceeded. (15.0s)
  attempt 2: Page.goto: Timeout 15000ms exceeded. (15.0s)
  price: $19.90
```

A página de bloqueio custou uma requisição e nenhuma espera; a página travada custou dois timeouts e depois deu certo. Novas tentativas guiadas por códigos de status, como `503` com `Retry-After`, ficam em uma camada separada; [Códigos de status HTTP no web scraping: 403, 407, 429, 503](/pt-br/blog/http-status-codes-web-scraping) traz esse código. O mesmo núcleo em Node.js:

```js
import { chromium, errors } from "playwright";

const PROXY = { server: "http://pr.proxynet.io:8000", username: "user", password: "pass" };
const URLS = ["https://shop.example.com/product/42", "https://shop.example.com/product/45"];

const browser = await chromium.launch({ proxy: PROXY });
for (const url of URLS) {
  const context = await browser.newContext();
  context.setDefaultNavigationTimeout(15_000); // goto, reload, waitForURL
  context.setDefaultTimeout(10_000);           // locators, cliques, esperas
  const page = await context.newPage();
  try {
    const response = await page.goto(url, { waitUntil: "domcontentloaded" });
    console.log(url, "status", response?.status(), "title", await page.title());
    console.log("  price:", await page.locator("#price").innerText());
  } catch (err) {
    if (!(err instanceof errors.TimeoutError)) throw err;
    console.log("  timeout:", err.message.split("\n")[0]);
  } finally {
    await context.close();
  }
}
await browser.close();
```

No nosso site de teste, a segunda página renderiza o preço depois de 12 segundos:

```text
http://shop.test/product/42 status 200 title Product
  price: $19.90
http://shop.test/product/45 status 200 title Product
  timeout: locator.innerText: Timeout 10000ms exceeded.
```

## Puppeteer: "Navigation timeout of 30000 ms exceeded"

O Puppeteer usa o mesmo modelo com outros nomes. O padrão dele também é de 30 segundos, `page.setDefaultNavigationTimeout()` e `page.setDefaultTimeout()` o alteram, e `waitUntil` aceita `load`, `domcontentloaded`, `networkidle0` e `networkidle2`. A [referência de eventos do ciclo de vida do Puppeteer](https://pptr.dev/api/puppeteer.puppeteerlifecycleevent) define os dois últimos como no máximo 0 ou 2 conexões abertas por 500 ms, então eles falham em páginas movimentadas, assim como o `networkidle`.

```js
import puppeteer, { TimeoutError } from "puppeteer";

const browser = await puppeteer.launch({ args: ["--proxy-server=http://pr.proxynet.io:8000"] });
const page = await browser.newPage();
await page.authenticate({ username: "user", password: "pass" });
page.setDefaultNavigationTimeout(15_000); // goto, reload, waitForNavigation
page.setDefaultTimeout(10_000);           // waitForSelector e outras esperas

try {
  const response = await page.goto("https://shop.example.com/product/45", { waitUntil: "domcontentloaded" });
  console.log("status", response?.status(), "title", await page.title());
  await page.waitForSelector("#price");
} catch (err) {
  if (!(err instanceof TimeoutError)) throw err;
  console.log(`${err.name}: ${err.message} (${err.cause?.message})`);
} finally {
  await browser.close();
}
```

As nossas execuções com Puppeteer 25.12 imprimiram estas mensagens; a primeira vem de uma página que nunca respondeu, com o limite padrão:

```text
TimeoutError: Navigation timeout of 30000 ms exceeded
TimeoutError: Waiting for selector `#price` failed (Waiting failed: 10000ms exceeded)
```

A mensagem do seletor omite o limite; ele fica em `err.cause`. O proxy entra como flag do Chromium e as credenciais, por `page.authenticate()`, que liga a interceptação de requisições em segundo plano. As causas e soluções acima valem sem mudanças.

## Onde você encontra esse erro

- **Scraping de lojas renderizadas com JavaScript:** os preços carregam depois do HTML, então espere o elemento ([extração de dados](/pt-br/data-scraping)).
- **Varredura de uma fila longa:** uma página travada deve custar um timeout, não a execução inteira ([web crawler](/pt-br/web-crawler)).
- **Testes do seu próprio aplicativo a partir de outros países:** cada IP de saída tem a sua própria latência, então defina limites por país ([testes de aplicativos](/pt-br/app-testing)).
- **Agentes de IA que controlam um navegador:** um agente que chama `goto` esbarra nos mesmos limites ([Playwright MCP](/pt-br/blog/playwright-mcp)).
- **Varreduras agendadas:** leia as regras de rastreamento do site antes de ajustar a velocidade ([O que é robots.txt e como ler o arquivo?](/pt-br/blog/robots-txt)).

## Erros comuns

- **Aumentar o padrão para 60 ou 120 segundos.** Uma espera que não tem como dar certo só falha mais tarde.
- **Tratar o `networkidle` como "pronto".** Páginas movimentadas nunca ficam em silêncio.
- **Pausas fixas antes de cada passo.** `time.sleep()` e `waitForTimeout()` são longas demais em páginas rápidas e curtas demais nas lentas.
- **Capturar só `TimeoutError` em volta de `expect()` em Python.** Ele lança `AssertionError`.
- **Pular o status e o título.** Uma página de bloqueio vira então um "elemento não encontrado" de 30 segundos.
- **Repetir requisições bloqueadas.** Novas tentativas servem para timeouts e quedas de rede, não para `403` e `429`.
- **Calar as camadas sobrepostas com `force=True`.** O clique cai onde um usuário não conseguiria clicar.

## Guia de decisão

| O que você vê | O que fazer |
|---|---|
| `page.goto: Timeout` com `waiting until "load"` | `domcontentloaded` e depois espere o elemento |
| `page.goto: Timeout` com `waiting until "networkidle"` | Abandone o `networkidle`; espere um elemento |
| `page.goto: Timeout` com `domcontentloaded` | Meça o tempo de carregamento pelo proxy e defina o limite a partir dele |
| `waiting for locator(...)` sem nada embaixo | Confira o seletor, os frames e em que página você está |
| `intercepts pointer events` | Feche a camada sobreposta como um usuário faria |
| Status `403` ou `429`, ou um título de bloqueio | Pare; diminua o ritmo, confira o `robots.txt`, peça permissão ou use uma API |
| `Test timeout of 30000ms exceeded.` | Encontre o passo que travou; aumente o limite só para testes lentos |
| `requestfailed` mostra `ERR_TUNNEL_CONNECTION_FAILED` | Corrija as credenciais do proxy antes de mexer nos timeouts |

## Perguntas frequentes

### Qual é o timeout padrão do Playwright?

Na biblioteca, 30 segundos para navegações e ações. No Playwright Test, um teste inteiro tem 30 segundos e cada `expect()`, 5 segundos; ações e navegações não têm um limite próprio.

### Como aumentar o timeout do page.goto?

Passe-o na chamada (`page.goto(url, timeout=60_000)` em Python, `{ timeout: 60_000 }` em Node.js), defina `set_default_navigation_timeout()` no contexto ou `navigationTimeout` na configuração do Playwright Test. Aumente só depois de medir.

### Por que o page.goto estoura o timeout se a página já aparece na tela?

O `goto` espera o evento `load` por padrão, e uma única imagem ou widget que nunca termina o segura. Use `domcontentloaded` e espere o elemento de que você precisa.

### Devo usar networkidle?

Não. A referência do Playwright o marca como desaconselhado, e páginas com polling ou chat ao vivo podem nunca alcançá-lo. Espere um elemento específico.

### Como capturar um TimeoutError do Playwright em Python?

Importe-o como `from playwright.sync_api import TimeoutError as PlaywrightTimeoutError` e capture esse nome. Um `expect()` que falha lança `AssertionError`.

### Um proxy pode causar timeouts no Playwright?

Sim. Um IP de saída lento pode empurrar as páginas além do limite, e credenciais erradas em um site HTTPS podem aparecer como timeout. Meça pelo proxy, defina os limites a partir dos resultados e escute o `requestfailed`. Uma página de bloqueio não se resolve com outro proxy.

## Em resumo

"Timeout 30000ms exceeded" aponta a espera que se esgotou, não a causa. Leia o método e o fim do call log e corrija o que eles indicam: uma espera por `load` ou `networkidle`, um seletor, uma camada sobreposta, um frame, uma página de bloqueio ou um IP de saída lento. Defina os limites no contexto a partir de tempos de carregamento medidos, dê à página lenta ocasional um limite próprio, tente de novo só nos timeouts, com backoff, e pare diante de bloqueios. Para escolher proxies que combinem com os seus alvos, compare [nossos serviços de proxy](/pt-br/proxy).
