Resolving Navigation Timeout Errors in Puppeteer
Learn how to diagnose and fix 'Navigation timeout exceeded' errors in Puppeteer by adjusting waitUntil strategies and navigation timeout settings.
12 Jul 2026, 18:00 UTC

The Problem: Navigation Timeout Exceeded
When calling page.goto() in Puppeteer, you may encounter a TimeoutError: Navigation timeout exceeded. By default, Puppeteer waits 30 seconds for the page to reach a specific lifecycle state. If the server is slow or a single third-party tracking pixel fails to load, the entire operation fails, even if the primary content is visible to the user.
Diagnostic Matrix
Use this table to match your symptoms to the most likely cause before attempting fixes.
| Symptom | Likely Cause | Diagnostic Indicator |
|---|---|---|
| Consistent failure at exactly 30s | Default timeout limit | Error log shows TimeoutError |
| Works in headful, fails in headless | Resource rendering differences | Visual check shows page loaded but spinner remains |
| Immediate or very fast timeout | Network/Proxy blockage | DNS lookup failure or 403/504 status |
| Intermittent failures on heavy pages | Hanging third-party assets | Network tab shows pending requests for ads/analytics |
Step-by-Step Resolution Path
Follow these checks in order. Do not jump to disabling timeouts (setting to 0) as this can create zombie browser processes that consume system memory.
1. Verify Visual State
Run the browser in headful mode to see if the page is actually stuck or if Puppeteer is simply waiting for a non-essential asset.
// Run this in your browser launch configuration
const browser = await puppeteer.launch({
headless: false
});
Observation: If the page looks complete but the script still throws a timeout, the issue is likely the waitUntil configuration.
2. Adjust the Navigation Lifecycle Strategy
Puppeteer's waitUntil option determines when the navigation is considered "finished." The default 'load' waits for the window load event, which includes all images and stylesheets.
domcontentloaded: Fires when the HTML is parsed. Use this if you only need the DOM and don't care about images.networkidle0: Waits until there are no more than 0 network connections for at least 500ms. Ideal for Single Page Applications (SPAs).networkidle2: Waits until there are no more than 2 network connections. Use this for pages with persistent polling or tracking scripts.
Example Implementation:
// Run this in your Puppeteer script
// Required permissions: Node.js environment with puppeteer installed
await page.goto('https://example.com', {
waitUntil: 'networkidle2', // More lenient than networkidle0
timeout: 60000 // Increase to 60 seconds for slow servers
});
3. Global Timeout Configuration
If multiple pages are timing out, set a global limit rather than modifying every goto call. This ensures consistency across your automation suite.
// Set this immediately after creating the page object
await page.setDefaultNavigationTimeout(60000);
Comparison of Wait Strategies
| Strategy | Wait Condition | Risk |
|---|---|---|
load |
Window load event | Fails if one image/pixel hangs |
domcontentloaded |
HTML parsed | Scripts may not have executed yet |
networkidle0 |
0 active connections | May never fire on pages with heartbeats |
Verification and Rollback
To verify the fix, monitor the process memory and the time to completion. If the script completes without the TimeoutError and the target element is present in the DOM, the fix is successful.
Rollback: If you modified setDefaultNavigationTimeout or waitUntil and the script now interacts with elements before they exist (causing NoSuchElement errors), revert the waitUntil setting to 'load' or 'networkidle0'.
Escalation Criteria
If the following conditions persist, the issue is likely outside of Puppeteer's configuration:
- The timeout occurs even when
timeout: 0is set (indicating a hard network hang). - The browser fails to launch or reach the first URL regardless of the
waitUntilstrategy. - The target site implements anti-bot measures that drop connections after the initial handshake.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.