Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Put browser cleanup in a finally block. That way, Puppeteer closes a browser your script launched whether page.goto() succeeds or rejects after a navigation timeout. Use await browser.close() to shut down that browser and its pages; if Puppeteer connected to a browser managed elsewhere, use browser.disconnect() instead so you detach without shutting down the remote browser.
Close the browser in a finally block
Puppeteer documents that Frame.goto() can throw when navigation exceeds its timeout, and that Browser.close() closes the browser and all associated pages. JavaScript’s finally block is the cleanup point for either outcome: it runs after the try body completes or throws. The following minimal pattern is suitable when a browser is launched for one navigation and should always be shut down:
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.goto(url, { timeout: 10_000 });
} finally {
await browser.close();
}
The timeout value is in milliseconds, so 10_000 means 10 seconds. Replace url with the URL you are navigating to. Puppeteer’s Frame.goto() documentation lists a timeout as one of the conditions that can throw; its Browser.close() reference describes the shutdown scope.
Preserve the navigation error if shutdown also fails
A finally block guarantees that cleanup is attempted, but a failure from browser.close() can itself become the error reported by the surrounding code. If you need to retain the original navigation error as well as report a shutdown error, capture the navigation failure and handle cleanup separately. This version records both and then rethrows the navigation error when one occurred:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
const browser = await puppeteer.launch();
let navigationError;
try {
const page = await browser.newPage();
await page.goto(url, { timeout: 10_000 });
} catch (error) {
navigationError = error;
} finally {
try {
await browser.close();
} catch (closeError) {
console.error('Could not close Puppeteer browser:', closeError);
}
}
if (navigationError) {
throw navigationError;
}
Adapt the reporting to your application: for example, send both errors to its logger or error-handling layer. Do not silently discard the close error. If navigation succeeded but closing failed, this example logs the shutdown failure and continues; change that policy if a failed shutdown must fail the job.
Choose the cleanup method by ownership and scope
The right method depends on what your script owns and what it intends to end. Puppeteer distinguishes shutting down a browser from detaching from one, and exposes narrower cleanup methods for pages and contexts.
| Method | Scope and effect | Use it when |
|---|---|---|
browser.close() |
Closes the browser and all its associated pages. | Your script launched the browser and is finished with that browser session. |
page.close() |
Closes one page, leaving the browser session available. | You want to discard the timed-out page but keep using the browser for other work. |
context.close() |
Closes a non-default isolated browser context and its pages. The default context cannot be closed. | Your script created a non-default context and is done with that isolated session. |
browser.disconnect() |
Detaches Puppeteer from an externally managed browser; it does not shut down that browser or close its pages. | Your script attached to a browser owned by another process and must leave it running. |
The distinction between browser.close() and browser.disconnect() matters most in automation services or shared browser setups: closing a remotely managed browser can affect work beyond the current Puppeteer client. See Puppeteer’s browser-management guide, Page API and BrowserContext.close() reference.
Keep a browser open but discard the failed page
If a timed-out navigation is one step in a longer session, closing the whole browser may be too broad. Close only the page when that is the intended recovery, and keep browser-level cleanup in the outer owner’s lifecycle:
Free tools Windows power users keep installed
One-click scans. No signup required.
Rank #2
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
try {
await page.goto(url, { timeout: 10_000 });
} catch (error) {
await page.close();
throw error;
}
// Continue browser work here if navigation succeeded.
} finally {
await browser.close();
}
This example still closes the browser at the end because this script launched it. If a different component owns the browser, that owner—not a helper that merely borrowed a page—should decide when to close the browser.
Set and interpret navigation timeouts
Puppeteer navigation timeouts are milliseconds. The current WaitForOptions reference documents a default of 30,000 ms and says that timeout: 0 disables the timeout. A per-navigation option can set the limit for one call; page.setDefaultNavigationTimeout(timeout) sets the default for navigation methods including goto, back/forward, reload, setContent and waitForNavigation. See the version-labeled WaitForOptions reference and Page class reference.
// One navigation only
await page.goto(url, { timeout: 20_000 });
// Or set the navigation limit for this page
page.setDefaultNavigationTimeout(20_000);
await page.goto(url);
Choose the timeout for the site and the lifecycle event your task waits for. Setting it to zero removes the time limit; that can leave a task waiting indefinitely if the page never reaches the selected event. A longer limit may be appropriate for a known slow navigation, but it does not fix an unreachable server or a page that cannot load.
Diagnose the actual navigation failure
A rejected goto() is not necessarily a timeout. Puppeteer’s Frame.goto() reference also lists SSL errors, invalid target URLs, unreachable or unresponsive servers, failed main-resource loads, and blocklist or allowlist restrictions as exception cases. Record or report the actual error rather than labeling every rejection as a timeout.
- Timeout exceeded: The navigation did not reach its awaited lifecycle condition before the configured limit. Check the URL, the site’s response and the selected wait condition; adjust the timeout only if the task reasonably needs more time.
- SSL error: The navigation failed during the secure connection or certificate checks. Investigate the target’s TLS setup and the runtime environment rather than treating a longer timeout as a fix.
- Invalid URL: Check that the value passed to
goto()is a valid target URL, including its scheme where required. - Unreachable or unresponsive server: Verify that the target is available from the machine running Puppeteer and that network access is working.
- Main-resource load failure: Inspect the target response and the error details; cleanup should still happen through
finally. - Blocklist or allowlist restriction: Check the restrictions applied by the environment or browser setup. Increasing the navigation timeout does not remove a policy restriction.
These categories reflect documented Frame.goto() exception conditions; the specific cause in a run must be determined from its actual error and environment. Frame.goto() API reference.
Common cleanup mistakes and fixes
Closing only after successful navigation
Code that calls browser.close() on the next line after await page.goto() will not reach that line if the navigation throws. Put cleanup in finally so both the success and error paths attempt it.
Closing the wrong resource
page.close() does not mean “shut down the browser”; it ends one page. browser.close() ends the browser and its pages. For an externally managed browser, browser.disconnect() detaches the client without ending the remote session. Match the API to the resource your code owns and intends to stop.
Using an unbounded wait as a timeout fix
timeout: 0 disables the timeout rather than making navigation more reliable. Use it only when indefinite waiting is acceptable and another mechanism controls the job’s lifetime.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteRank #4
Replacing the original error with a cleanup error
If shutdown also rejects, make the error policy explicit: log both failures, preserve the navigation error when it is the primary failure, and ensure the shutdown failure is visible to monitoring. Avoid an empty catch that hides a browser process that may not have closed.
Performance, reliability and cost considerations
Cleanup belongs in the same layer that owns the browser lifecycle. Closing the whole browser ends all of its pages, while closing a page or context has a narrower effect; using the narrowest appropriate scope avoids ending work the script intends to keep. Conversely, when a script launches a browser for a single job, failing to close it after a rejected navigation can leave browser resources alive beyond that job.
There is no universal timeout value in the cited API references that guarantees fast or reliable navigation for every site. A longer limit trades a longer possible wait for fewer premature timeout failures on slow tasks; disabling it removes that bound altogether. The navigation timeout itself is not a browser cleanup mechanism, so do not rely on it to stop the launched browser. The documentation cited here does not establish a monetary cost per timeout or a performance benchmark; account for resource use and job limits according to your runtime or hosting provider.
Or skip the browser setup
If your goal is a website screenshot rather than controlling a browser session, ScreenshotNeo offers a screenshot API: one GET request can return a PNG, JPEG, WebP or PDF. For example, this cURL request saves a WebP shot:
Best Value
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for request options. Cookie banners are accepted before capture and 60+ known consent platforms, newsletter popups and chat widgets can be removed; each of those steps can be turned off. Bot checks/CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing, and response headers identify the page verdict and billing status. An MCP server provides take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots.
Create a free ScreenshotNeo account to try 1,000 screenshots a month with no card.
Frequently Asked Questions
Does a navigation timeout automatically close the Puppeteer browser?
No. The timeout is a navigation failure condition; your script must perform browser cleanup, such as in a finally block.
Which Puppeteer API should I use if the browser belongs to another process?
Use browser.disconnect() to detach the Puppeteer client without shutting down the externally managed browser.
Quick Recap
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.

