DriversRecommendedOutdated drivers can make a good PC feel brokenScan driver issues before chasing fixes manually.Scan NowOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix Now×
Skip to content
browser automation

How to Fix Inconsistent Navigation Timeouts in Puppeteer

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

Puppeteer navigation timeouts are reliable symptoms, not diagnoses. A page.goto() or page.waitForNavigation() timeout means the navigation wait did not observe its configured completion condition before the deadline. It does not necessarily mean the server was slow. First identify the rejecting method, then match the wait to what your workflow actually needs, register click waits before the click, and change a timeout only after confirming that the condition is correct and merely slow.

Identify which timeout is actually failing

Start by recording the complete error text, the exact line that rejects, your Puppeteer version, browser version, URL, call-level options, and page-level timeout configuration. Puppeteer uses separate timeout families, so changing a navigation timeout cannot fix an element wait or browser-launch failure.

Rejecting operation What it is waiting for Relevant controls
page.goto(), page.reload(), page.goBack(), page.goForward(), page.setContent(), or page.waitForNavigation() A navigation completion condition Per-call timeout; page.setDefaultNavigationTimeout(); also affected by the general page default
page.waitForSelector(), waitForResponse(), or waitForRequest() A selector, response, or request event Per-call timeout or page.setDefaultTimeout()
Locator actions Visibility, enabled state, and a stable bounding box before interaction Page timeout by default; an individual locator timeout can be set
puppeteer.launch() Browser startup LaunchOptions.timeout, a separate launch setting

The current Puppeteer API reference (version 25.12.0) documents a 30,000-millisecond default for wait options and a 30,000-millisecond browser-start default. A wait timeout of 0 disables that timeout. These are documented defaults, not measurements of your page’s performance.

Understand the timeout and wait scopes

Per-call options take priority

Set a timeout and completion event on the operation whose behavior you are diagnosing:

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.
await page.goto('https://example.com', {
  waitUntil: 'domcontentloaded',
  timeout: 45_000
});

The waitUntil default is 'load'. You can provide one lifecycle event or an array. The operation succeeds only when the selected condition occurs within the timeout.

Page-wide defaults

page.setDefaultNavigationTimeout(timeout) changes the default maximum for navigation methods, including goto, history navigation, reload, setContent, and waitForNavigation. page.setDefaultTimeout(timeout) sets the general page default used by selector, request, response, and other waits; it is also the inherited default for locator actions. Query the navigation value with page.getDefaultNavigationTimeout() while debugging.

page.setDefaultNavigationTimeout(45_000);
page.setDefaultTimeout(20_000);
console.log('navigation timeout:', page.getDefaultNavigationTimeout());

Keep these settings deliberate. A very large global value can make a genuine defect look like a hung test, while a small value can fail a healthy but variable page. Prefer a measured per-call override when only one route is slow.

Browser startup is different

const browser = await puppeteer.launch({ timeout: 60_000 });

This controls how long Puppeteer waits for the browser process to start. It does not extend a page navigation. Diagnose launch errors separately from page errors.

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

Prevent the click/navigation race

If a click can trigger a document navigation, subscribe to navigation before dispatching the click. Waiting in two sequential statements can miss a fast navigation and leave waitForNavigation() waiting for an event that already happened.

const [response] = await Promise.all([
  page.waitForNavigation({
    waitUntil: 'domcontentloaded',
    timeout: 30_000
  }),
  page.click('a.my-link')
]);

console.log('main-resource response:', response ? response.status() : 'none');

The promise array starts both operations immediately; the navigation listener is installed before the click runs. Use a locator for the action when appropriate, but keep the navigation wait in the same concurrency pattern:

const link = page.locator('a.my-link');
await Promise.all([
  page.waitForNavigation({ waitUntil: 'load' }),
  link.click()
]);

Do not assume every URL change produces a response. Puppeteer treats History API URL changes as navigation, and anchor changes can also count, but waitForNavigation() resolves with null when there is no main-resource response.

Choose a completion signal that matches the application

Document navigation

Use domcontentloaded when the next action only needs the parsed document. Use load when the page’s load event is the required boundary. Neither event guarantees that a client-rendered dashboard is usable.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
await page.goto(url, { waitUntil: 'domcontentloaded' });
await page.locator('#results').wait();

Network-idle conditions

Network-idle waits are appropriate only when network quiet is genuinely your readiness criterion. Applications with analytics, WebSockets, polling, streaming, or recurring fetches may never become quiet, so a network-idle timeout can be expected behavior rather than evidence of a broken navigation.

Single-page applications

For an SPA route change, wait for the state your next step consumes: an expected URL, a specific response, or a DOM element containing the result. A URL change alone does not prove that rendering or data loading is complete.

await page.click('button[data-route="reports"]');
await page.waitForFunction(
  () => location.pathname === '/reports',
  { timeout: 30_000 }
);
await page.locator('[data-testid="report-table"]').wait();

If an API response is the meaningful boundary, subscribe before the action:

const [apiResponse] = await Promise.all([
  page.waitForResponse(
    response => response.url().endsWith('/api/reports') && response.ok()
  ),
  page.click('#load-reports')
]);
console.log(await apiResponse.json());

For a selector, use waitForSelector or a locator wait rather than extending navigation indefinitely. These waits have their own timeout behavior and should describe the actual readiness requirement.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Best Value
The SQL Programming Language: .
  • Used Book in Good Condition

Use a deterministic diagnostic workflow

  1. Capture the failure. Save the full TimeoutError, rejecting method, URL, versions, and all explicit options.
  2. Classify the wait. Decide whether it is browser startup, navigation, locator/action, selector, request, or response.
  3. Inspect scope. Search for per-call timeout and waitUntil, then review every call to setDefaultTimeout and setDefaultNavigationTimeout. Log getDefaultNavigationTimeout().
  4. Remove races. Put click-triggered navigation or response waits in Promise.all, with the wait first.
  5. Define ready. Select a lifecycle event, URL, response, or DOM state based on the next operation—not habit.
  6. Log boundaries. Record timestamps before and after the action, the observed URL, response status when available, and whether the expected selector appeared.
  7. Reproduce consistently. Keep browser version, network conditions, authentication state, viewport, and page data the same while isolating the failure.
  8. Change one value. Increase a timeout only after the correct condition is observed regularly taking longer than the current limit.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Common failure patterns and fixes

Symptom Likely explanation Fix
waitForNavigation always times out after a button click The click updates SPA state or fires an API request instead of loading a document, or the listener was registered too late. Register the wait before clicking; otherwise wait for the expected URL, response, or result element.
Timeout occurs only with waitUntil: 'networkidle0' Background polling or persistent connections prevent the selected quiet condition. Use a lifecycle event plus an application-specific readiness check.
goto times out, but the page eventually appears The selected event takes longer than the deadline, or a subresource keeps the event from arriving. Measure the event; use the earliest sufficient waitUntil and a targeted readiness wait. Increase the timeout only if that event is correct.
Changing navigation timeout has no effect on a selector failure The rejecting call uses the general page timeout or its own option. Set the selector/locator timeout or adjust setDefaultTimeout.
Browser launch fails before a page exists The startup deadline is separate from page navigation. Inspect launch arguments and process startup, then adjust launch({ timeout }) if startup is legitimately slow.
Navigation returns null History API or anchor navigation changed the browsing state without a main-resource response. Treat the URL or DOM state as the completion signal; do not require an HTTP response.

Timeout design for reliable test suites

  • Use the smallest condition that proves readiness. A document event followed by a result-element wait is usually clearer than an unbounded network-idle wait.
  • Keep global defaults conservative and make exceptional routes explicit at the call site.
  • Never use timeout: 0 as a blanket reliability fix. It disables the guard and can leave workers stuck forever; reserve it for a deliberately controlled operation with an external watchdog.
  • Separate navigation timing from application timing. A fast document can still have a slow API, and a slow document does not justify waiting for an API that never runs.
  • Make logs identify the condition, not just the duration: “waiting for load,” “waiting for reports response,” and “waiting for report-table locator” lead to different fixes.

Or skip the browser setup

If your actual goal is a dependable screenshot rather than browser automation, ScreenshotNeo provides a single HTTP request. It accepts the cookie or consent banner like a visitor, removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture, and lets you turn each cleanup step off. Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, with X-Page-Verdict and X-Billed headers explaining the result.

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}`);

See the ScreenshotNeo documentation for options such as full-page lazy-image capture, CSS-selector element shots, device and retina settings, custom CSS or JavaScript, click and wait rules, request blocking, headers, cookies, geolocation, PDFs, caching, signed links, asynchronous webhooks, bulk capture, and the usage API. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots, and every feature is available on every plan. Create a free ScreenshotNeo account.

FAQ

What is Puppeteer’s default navigation timeout?

The current API reference documents 30,000 milliseconds for wait options. A per-call setting or page default can override it, and 0 disables the timeout.

Should I always use networkidle0?

No. Use it only when network quiet is meaningful for the workflow. Polling and persistent connections can prevent it from completing.

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

Why is waitForNavigation() returning null?

History API and anchor navigations can count as navigation without a main-resource response. Verify the URL or application state instead of expecting an HTTP response.

Frequently Asked Questions

Can I set different navigation and selector timeouts?

Yes. Use a per-call timeout for each wait, or configure navigation with setDefaultNavigationTimeout and general waits with setDefaultTimeout.

Does a locator solve navigation timing?

A locator waits for action preconditions such as visibility, enabled state, and a stable bounding box; it does not define when navigation or SPA rendering is complete.

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.

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

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
Crashes, No Sound, or Screen Glitches?Free driver scan
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.