October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run ScanOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
browser automation

How to Fix Puppeteer Navigation Timeout Errors (Including `Navigation timeout of 30000 ms exceeded`)

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Fix Puppeteer navigation timeouts by identifying the operation that hit its deadline, choosing a readiness condition your page can actually satisfy, and setting the smallest timeout that fits the job. Use a per-call timeout for exceptional pages, page.setDefaultNavigationTimeout() for a deliberate page-wide policy, and register navigation or response waits before the click or request that triggers them.

What the error means

Navigation timeout of 30000 ms exceeded means Puppeteer waited 30 seconds for a navigation-related operation to complete. The deadline may have expired while loading a URL, reloading, going back, waiting for a navigation event, or waiting for a selected waitUntil condition. A TimeoutError is shared by several Puppeteer APIs, so the operation named in the stack trace matters more than the word “navigation.”

The documented default for common navigation and wait operations is 30 seconds. Where an option documents it, timeout: 0 removes that deadline; use zero only when your own cancellation or job limit prevents a stuck page from holding a worker forever.

Start with a precise diagnosis

  1. Record the operation. Note whether the failure came from page.goto(), reload(), waitForNavigation(), waitForResponse(), a selector wait, or another call.
  2. Log the URL and settings. Include the URL, timeout value, and waitUntil value in the error log. This distinguishes a slow server from a readiness condition that can never be true.
  3. Check whether the browser stayed alive. A closed browser, page, or target is a separate failure. Increasing a timeout will not repair a crashed target.
  4. Reproduce the URL outside Puppeteer. If it also fails in a normal browser or through your network, investigate DNS, proxy, TLS, authentication, WAF or bot checks, and server latency before changing Puppeteer code.

For page.goto(), pass a fully qualified URL such as https://example.com. The method navigates the frame or page to that URL and, when applicable, resolves with the response for the final redirect. It can resolve to null for documented cases such as about:blank. A successful HTTP status still does not prove that your application rendered the state your test needs.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Set a timeout at the right scope

Use a per-navigation timeout first

A local timeout limits the change to one call, which is usually safest when only one endpoint is slow:

await page.goto(url, {
  waitUntil: 'domcontentloaded',
  timeout: 60000
});

This keeps other navigations on their normal policy and makes the exception visible at the call site.

Set a page-wide default deliberately

page.setDefaultNavigationTimeout(timeout) changes the default maximum for goto, reload, goBack, goForward, setContent, and waitForNavigation. Use getDefaultNavigationTimeout() to find an inherited value while diagnosing:

page.setDefaultNavigationTimeout(60000);
console.log('navigation timeout:', page.getDefaultNavigationTimeout(), 'ms');

A page-wide value is useful when all routes in a controlled environment share similar latency. It is risky when a permanently broken URL can consume a worker for a long time. Keep an outer job deadline as well.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose a waitUntil condition that can finish

Condition Use it when Typical failure mode
domcontentloaded The initial DOM is enough to begin your next explicit readiness check. Images, fonts, or client data are not ready yet.
load Required subresources must finish loading before you continue. One slow asset or third-party resource holds the event.
networkidle0 The page is expected to become completely quiet. Polling, analytics, ads, streams, or open sockets keep traffic active indefinitely.
networkidle2 You can tolerate up to a small amount of continuing network activity. A site with frequent background requests still never reaches the condition.

Network-idle conditions are not universal “page ready” signals. Single-page applications commonly fetch data after the initial document, while dashboards and chat pages intentionally keep connections open. Prefer a less restrictive navigation condition, then wait for the concrete evidence your test needs: a selector, URL change, response, or application-ready marker.

await page.goto('https://example.com/products', {
  waitUntil: 'domcontentloaded',
  timeout: 30000
});
await page.waitForSelector('[data-testid="product-list"]', {
  visible: true,
  timeout: 15000
});

This separates “the document arrived” from “the product list exists,” giving each requirement its own diagnosable timeout.

Fix clicks that trigger navigation or API requests

Register waitForNavigation() before the click

The wait must be created before the action that triggers navigation. Otherwise the event can occur before Puppeteer starts listening, leaving the wait to time out:

const navigation = page.waitForNavigation({
  waitUntil: 'domcontentloaded',
  timeout: 30000
});
await page.click('a.next');
await navigation;

If the click sometimes changes the URL without a full document navigation, waiting for a URL or application marker may be more reliable than waitForNavigation().

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Register waitForResponse() before an API-triggering action

const responsePromise = page.waitForResponse(
  response => response.url().includes('/api/items'),
  { timeout: 30000 }
);
await page.click('#load-items');
const response = await responsePromise;
if (!response.ok()) {
  throw new Error(`Items request failed: ${response.status()}`);
}

When a request can be retried or multiple matching responses exist, make the predicate more specific by checking the HTTP method, query string, or response status.

Verify redirects, content, and authentication

Capture the response returned by navigation and inspect the final URL:

const response = await page.goto('https://example.com/account', {
  waitUntil: 'domcontentloaded',
  timeout: 60000
});
console.log({
  status: response?.status() ?? null,
  finalUrl: page.url()
});

await page.waitForSelector('main', { timeout: 15000 });

A 200 response can still be a login page, an error template, or a bot-check screen. Check a title, URL, selector, or application state that proves the expected page loaded. If authentication is required, establish the session before navigation and confirm that redirects do not send the browser to a sign-in or challenge page.

Timeout strategies compared

Strategy Readiness guarantee Maximum wait cost Scope
Raise one goto timeout Only the chosen waitUntil condition is guaranteed. Bounded by that call’s larger deadline. One navigation.
Use domcontentloaded plus a selector/response wait Directly checks the content your test needs. Two explicit, independently bounded waits. One workflow; usually the clearest diagnosis.
Use networkidle0 or networkidle2 Only proves that the chosen network-activity threshold was reached. Can consume the full timeout on polling or streaming pages. One navigation, but sensitive to site behavior.
Set a page-wide default Does not change readiness semantics. Every covered operation can use the larger deadline. All covered navigations on the page.
timeout: 0 No built-in deadline. Unbounded unless your job supplies cancellation. One call where supported.

Common failure patterns and fixes

The URL is incomplete or redirects unexpectedly

Symptom: Navigation fails immediately or ends on an unexpected page. Fix: Include https://, log the final URL and status, and verify redirect and authentication behavior.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

networkidle0 never arrives

Symptom: The page is visibly usable but the timeout fires. Fix: Switch to domcontentloaded or load, then wait for a specific selector, response, URL, or ready marker.

The click wait is registered too late

Symptom: A click visibly navigates, but waitForNavigation() times out. Fix: Create the promise before click() and await it afterward.

The server or network is genuinely slow

Symptom: The same URL is slow outside Puppeteer. Fix: Investigate DNS, proxy, TLS, WAF, credentials, and server latency; then use a measured per-call timeout rather than an unlimited global value.

The browser target closed

Symptom: Errors mention a closed page, target, or browser. Fix: Handle process crashes, browser disconnects, memory pressure, and premature cleanup separately from navigation timing.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A valid response contains the wrong application state

Symptom: Navigation resolves, but assertions fail later. Fix: Add an explicit readiness assertion immediately after navigation and report the observed URL, title, or marker in the failure.

Make retries and workers safe

  • Set separate budgets for navigation, selector, and response waits so one stuck condition cannot consume the entire job.
  • Keep an outer task deadline shorter than your queue’s lease or serverless execution limit.
  • Retry transient network failures with a small, capped number of attempts; do not blindly retry deterministic selector or authentication failures.
  • Log the selected waitUntil, effective timeout, final URL, status, and which readiness check failed.
  • Use a controlled test page or a stable application marker when you need reproducible timing.

Longer timeouts increase reliability only when the page eventually satisfies the same condition. They increase cost and reduce throughput when the condition is impossible, so fix the condition first.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your actual goal is to obtain a website image or PDF rather than run an interaction test, ScreenshotNeo provides a single screenshot API request. It is not a repair for Puppeteer tests, but it avoids managing Chromium, navigation waits, and rendering infrastructure for capture jobs.

ScreenshotNeo removes cookie/consent banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and each response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For the complete parameter list, see the ScreenshotNeo documentation.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

It supports PNG, JPEG, WebP, and PDF output plus full-page capture, lazy-image loading, CSS-selector element capture, dark mode, device presets, custom viewport and retina scale, PDF paper and page-range controls, custom CSS/JavaScript, clicks, selector waits, delays, network-idle waits, request and resource blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, configurable caching, signed links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage data, and an OpenAPI specification. Parameter names used by other screenshot APIs also work, which can simplify migration.

Plans include 1,000 screenshots per month free with no card; paid plans start at $5 for 3,000 screenshots. Every feature is on every plan. Create a free ScreenshotNeo account.

FAQ

Does increasing the timeout fix every 30-second error?

No. It helps only when the page will eventually satisfy the same condition. A missed event, never-idle network, wrong URL, or closed target needs a different fix.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Should I always use networkidle0 for screenshots?

No. It can wait forever on pages with polling, streams, ads, or persistent sockets. Use it only when complete network quiescence is meaningful for that page.

Why does waitForNavigation() time out after a successful click?

The click may update the application without a document navigation, or the wait may have been registered after the event. Choose a selector, URL, or response wait for the behavior the click actually produces.

When is timeout: 0 appropriate?

Only when your surrounding job has its own cancellation and maximum runtime. Otherwise a hung page can occupy a worker indefinitely.

Frequently Asked Questions

Can a 200 HTTP status still indicate a failed Puppeteer test?

Yes. The response may be a login page, bot challenge, or error template. Verify the expected URL, selector, or application-ready marker.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Which timeout should I change first?

Start with a per-call timeout on the operation named in the stack trace. Change the page-wide default only when the policy should apply to all covered navigation methods.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Read next

Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.