Timeouts
Browser automation involves multiple timeout layers. Understanding which layer causes a given failure makes errors much easier to diagnose and fix.
The Timeout Chain
Timeouts operate from innermost (your code) to outermost (infrastructure):
Code-level timeouts
These are timeouts you set in your Puppeteer or Playwright code:
page.goto()navigation timeout (default 30,000ms in Puppeteer/Playwright)page.waitForSelector()timeoutbrowserType.connect()connection timeout (how long to wait to establish the WebSocket connection)
These are controlled entirely by your code and your library version. Increase them via gotoOptions.timeout in REST API calls, or page.setDefaultNavigationTimeout() in library code.
Session timeout
The maximum lifetime of a browser session. When a session reaches this limit, Browserless terminates it regardless of what it is doing.
Configure it two ways:
- Per-request: Add
&timeout=<milliseconds>to the connection URL. Example:wss://chrome.browserless.io?token=YOUR_TOKEN&timeout=120000 - Global default: Set the default for all sessions in your cluster dashboard under Settings → Timeout.
The default is 300,000ms (5 minutes). This acts as a safety net for sessions that hang or are not properly closed by your code. See Worker Settings.
Queue timeout
When all concurrency slots are full, new connection requests wait in a queue. If no slot opens in time, Browserless rejects the queued request.
Configure queue length in the dashboard under Settings → Queue. If you want immediate 429 errors instead of queuing, set queue length to 0. See Worker Settings.
Infrastructure timeout
The load balancer closes connections that hold open without sending or receiving data for an extended period. This timeout is not configurable. Your client receives a connection reset or generic timeout error, not a specific error code.
This is usually a symptom of concurrency pressure: requests waiting in the queue with no data moving. Address it by reducing concurrent load or adding workers.
Self-Hosted Timeout Considerations
WebSocket Heartbeat Interval
The enterprise image sends WebSocket heartbeat pings every 30 seconds by default (HEARTBEAT_INTERVAL env var). Load balancers with idle connection timeouts shorter than the heartbeat interval close connections silently. Set HEARTBEAT_INTERVAL below your load balancer's idle timeout. Common defaults:
- AWS ALB: 60 seconds
- NGINX
proxy_read_timeout: 60 seconds - Azure Container Apps: 240 seconds
Per-Connection Timeout Override
Add ?timeout=<milliseconds> to the WebSocket connection URL to override the global TIMEOUT for a single session:
ws://host:3000/chromium?token=TOKEN&timeout=300000
Timeout Independence
These timeouts are all separate and must each be configured explicitly:
| Timeout | Controls | Configuration |
|---|---|---|
| Session timeout | How long the entire session lives | TIMEOUT env var or ?timeout= query param |
| Reconnect timeout | How long the browser waits for a reconnection after disconnect | timeout parameter in Browserless.reconnect CDP command |
| LiveURL timeout | How long the LiveURL stream stays active | timeout parameter in Browserless.liveURL CDP command |
| MAX_RECONNECT_TIME | Caps the maximum reconnect timeout any client can request | MAX_RECONNECT_TIME env var. Default: Infinity |
Reverse Proxy Alignment
Your reverse proxy's read/idle timeout must exceed the TIMEOUT env var. If NGINX closes a connection at 60 seconds but TIMEOUT is 300 seconds, the client receives a connection reset with no Browserless error code. Example NGINX alignment:
proxy_read_timeout 600s; # Must exceed TIMEOUT (300000ms = 300s, add buffer)
proxy_send_timeout 600s;
Common Timeout Errors
| Error | Likely cause | Fix |
|---|---|---|
browserType.connect: Timeout Xms exceeded | Fleet at capacity, wrong URL, or network issue | Verify URL, check fleet concurrency, increase connection timeout |
Navigation timeout of 30000 ms exceeded | Target page loaded too slowly | Increase gotoOptions.timeout |
waiting for fonts to load in screenshot timeout | Web fonts loading slowly during capture | Ensure fonts load before calling screenshot; check for slow font CDNs |
| HTTP 408 | waitForEvent event never fired before timeout | Verify the event name and that your page actually dispatches it |
| HTTP 429 | Queue is full | Implement backoff, reduce concurrency, or increase queue length |
HTTP 500 Health checks have failed, rejecting | Worker CPU/memory above 90% | Stagger burst requests, reduce concurrency, or add workers |
Target page, context or browser has been closed | Session timed out or crashed while an operation was in progress | Add error handling, verify timeout settings |
Protocol error (Network.getResponseBody): No data found | Session crashed or page navigated away during a network operation | Add error handling; if persistent, contact support (may indicate memory pressure on the worker) |