Puppeteer: Navigation timeout of 30000 ms exceeded
Last verified
TimeoutError: Navigation timeout of 30000 ms exceededWhat it means
A navigation started by page.goto(), page.waitForNavigation(), page.reload() or page.goBack() did not reach its waitUntil condition within the navigation timeout, 30 seconds by default. The default condition is load, which waits for every image, script, stylesheet and iframe on the page. networkidle0 and networkidle2 are stricter still, requiring the network to go quiet for 500 ms.
The message does not say which resource held the page open. Very often the HTML arrived quickly and the document is usable; a slow analytics script, a hanging ad request or a long-polling connection simply kept the load event from firing. A second common pattern is page.waitForNavigation() started after a click whose navigation had already completed, so it waits for a navigation that never comes.
What is not wrong: DNS and connectivity. Those fail fast with net::ERR_... errors instead.
What it looks like
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com/', { waitUntil: 'domcontentloaded' });
await page.waitForSelector('h1');
// Click that causes a full navigation
await Promise.all([
page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
page.click('a.next'),
]);
await browser.close();Why it happens
- waitUntil: 'networkidle0' on a page with analytics, websockets or long-polling, so the network never goes idle.
- A third-party resource (ads, chat widget, fonts) loads slowly and delays the load event.
- page.waitForNavigation() is awaited after the click, missing a navigation that already finished.
- The click triggers a client-side route change (history.pushState), which is not a full navigation in the default sense.
- A bot-protection challenge, slow proxy or overloaded server delays the response.
How to fix it
- Wait for less: page.goto(url, { waitUntil: 'domcontentloaded' }) and then wait for the element you need.
- Start the navigation wait before the click: await Promise.all([page.waitForNavigation(), page.click('a.next')]).
- For single-page apps, wait for a selector or URL change rather than a navigation event.
- Abort irrelevant requests with page.setRequestInterception(true) and request.abort() for images, fonts or trackers.
- Raise the limit only when the page is genuinely slow: page.setDefaultNavigationTimeout(60000) or { timeout: 60000 }.
How to stop it recurring
Separate "the document arrived" from "the content I need is ready": navigate with domcontentloaded and then wait for a concrete selector. Avoid networkidle0 on modern sites. Always arm waitForNavigation before the action that triggers it, and block heavy third-party traffic in scraping jobs where it adds nothing.
Official documentation: pptr.dev/api/puppeteer.page.goto. See all Puppeteer error messages.
Related errors
- TimeoutError: Waiting for selector failedTimeoutError: Waiting for selector `.results` failed [cause]:…
- net::ERR_NAME_NOT_RESOLVED at <url>Error: net::ERR_NAME_NOT_RESOLVED at https://exmaple.com/
- Execution context was destroyed, most likely because of a navigationError: Execution context was destroyed, most likely because of a navigation.
Definitions
- PuppeteerPuppeteer is Google's open-source Node.js library for controlling Chrome and Firefox. It drives Chrome over th
- Chrome DevTools Protocol (CDP)The Chrome DevTools Protocol (CDP) is the JSON-over-WebSocket interface Chrome exposes for inspecting and cont
- CSS SelectorA CSS selector is a pattern used to identify and target specific HTML elements on a web page, widely used in b
- Headless ChromeHeadless Chrome is Google Chrome running without a visible window. It renders pages and runs JavaScript like n
- IframeAn iframe (inline frame) is an HTML element that embeds a separate web page within a parent page, creating an
- Web ElementA web element is any individual component rendered on a web page — buttons, links, input fields, images, text
Quick answers
What does "Navigation timeout of 30000 ms exceeded" mean in Puppeteer?
A navigation started by page.goto() , page.waitForNavigation() , page.reload() or page.goBack() did not reach its waitUntil condition within the navigation timeout, 30 seconds by default. The default condition is load , which waits for every image, script, stylesheet and iframe on the page. networkidle0 and networkidle2 are stricter still, requiring the network to go quiet for 500 ms.
How do I fix "Navigation timeout of 30000 ms exceeded"?
1. Wait for less: page.goto(url, { waitUntil: 'domcontentloaded' }) and then wait for the element you need. 2. Start the navigation wait before the click: await Promise.all([page.waitForNavigation(), page.click('a.next')]). 3. For single-page apps, wait for a selector or URL change rather than a navigation event. 4. Abort irrelevant requests with page.setRequestInterception(true) and request.abort() for images, fonts or trackers. 5. Raise the limit only when the page is genuinely slow: page.setDefaultNavigationTimeout(60000) or { timeout: 60000 }.
Run browser automation you can watch and take over
Autonoly runs each job in a real cloud Chromium browser driven by Playwright. Timeouts and detached elements still happen; the difference is that you can watch the run live, see the step that failed, and take control of the browser to finish it.
Also see Live browser control.