How to Set a Timeout for Puppeteer Wait Operations
Set a timeout in milliseconds for one Puppeteer wait, change the page default, or adjust navigation and locator timeouts. See the scope, code, and fixes for common errors.
Set the timeout option on a Puppeteer wait when only that operation needs a different limit. Values are milliseconds. For broader changes, use page.setDefaultTimeout(ms) for the page’s general default, page.setDefaultNavigationTimeout(ms) for navigation operations, or locator.setTimeout(ms) for locator actions. The current Puppeteer reference documents a 30,000 ms default for WaitForOptions; a timeout of 0 disables the timeout where documented. Choose the narrowest setting that matches the operation. (WaitForOptions, Page.setDefaultTimeout, Page.setDefaultNavigationTimeout)
Choose the timeout scope
| What needs a different limit? | Use | Scope |
|---|---|---|
| One selector or other wait | { timeout: ms } in that operation’s options |
That call |
| General page operations | page.setDefaultTimeout(ms) |
Page default for applicable operations |
| Navigation | page.setDefaultNavigationTimeout(ms) |
Navigation methods and waits documented by Puppeteer |
| Locator actions | locator.setTimeout(ms) |
Actions using that locator |
Use an explicit per-call timeout when one wait is unusual. Use the page default if the same general limit makes sense across relevant operations. Use the navigation default when the delay is specifically in navigation. These settings have different scopes, so raising one does not necessarily change every wait. Puppeteer documents the navigation default for goBack, goForward, goto, reload, setContent, and waitForNavigation. (Page.setDefaultNavigationTimeout)
Set a timeout for one wait
Pass the timeout in the options object for the wait you want to change:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.goto('https://example.com');
// Wait up to 10 seconds for this selector.
await page.waitForSelector('.result', { timeout: 10_000 });
console.log('Result appeared');
} finally {
await browser.close();
}
})();
waitForSelector() resolves immediately if the selector is already present. If it does not appear before the timeout, Puppeteer throws. Its options also include visible, hidden, and an abort signal; the wait works across navigations. With hidden: true, the wait can resolve to null when the selector is absent, which is a successful hidden-state outcome rather than a timeout error. (Page.waitForSelector)
Change page defaults
Set the general page timeout before the operations that should use it. Set a separate navigation timeout if navigation needs a different limit:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
// General default for applicable page operations: 10 seconds.
page.setDefaultTimeout(10_000);
// Navigation default: 20 seconds.
page.setDefaultNavigationTimeout(20_000);
await page.goto('https://example.com');
await page.waitForSelector('main');
} finally {
await browser.close();
}
})();
setDefaultTimeout() changes the page’s default maximum time. setDefaultNavigationTimeout() changes the navigation default. Keep both settings explicit if you intentionally want different limits; do not assume the navigation setting controls selector waits. (Page.setDefaultTimeout, Page.setDefaultNavigationTimeout)
Set a locator action timeout
For locator actions, set a total timeout on the locator. This returns a locator configured with that limit; its documented default comes from Page.getDefaultTimeout().
const button = page.locator('button.submit').setTimeout(10_000);
await button.click();
A timeout of 0 disables the locator timeout. Use that only when waiting indefinitely is intentional. (Locator.setTimeout)
Wait for navigation after a click
If a click triggers navigation, start waiting for the navigation before clicking. Otherwise, a fast navigation can begin before the wait is registered. Puppeteer documents this Promise.all() pattern:
const [response] = await Promise.all([
page.waitForNavigation({ timeout: 20_000 }),
page.click('a.next'),
]);
console.log('Navigation completed', response?.status());
The response can be null for navigations that do not produce a new HTTP response, such as certain same-document navigations. Do not assume every successful navigation has a response object. (Page.waitForNavigation)
Timeout behavior and options
- Units: timeout values are milliseconds. For example,
10_000is 10 seconds. - Documented default: the current
WaitForOptionsreference lists 30,000 ms (30 seconds). This is an API default, not a guarantee that a page or operation will finish in that time. (WaitForOptions) - Disable a timeout:
0disables it for the cited wait or locator option. An unbounded wait can leave a script stuck if its condition never occurs, so use it only when indefinite waiting is intended. - Selector state: selector waits can request
visibleorhidden. A selector existing in the DOM is not necessarily visible; choose the state that matches what the next step requires. (Page.waitForSelector) - Abort signal:
waitForSelectoraccepts an abort signal in its options. Use cancellation when the caller may no longer need the result; handle the resulting rejection as cancellation rather than treating it as a timeout. (Page.waitForSelector)
Timeout examples here are illustrative. Pick limits based on the operation and environment; increasing a timeout does not repair a selector mismatch, failed navigation, or a page that never reaches the desired state.
Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
waitForSelector times out |
The selector never appears, is incorrect, or the expected content is not reached. | Check the selector and page state. Confirm the page reached the expected route, then wait for the specific element the next step needs. Increase the per-call limit only if the condition is correct and can reasonably take longer. |
| The element exists but the action still fails | The wait checked for DOM presence, while the action requires a visible or actionable element. | Use the relevant visibility option where appropriate, and inspect whether an overlay or other page state prevents the action. |
goto or waitForNavigation times out after changing the page default |
The general page timeout and navigation timeout have different scopes. | Set page.setDefaultNavigationTimeout(ms) or pass a timeout to the navigation call. |
| Click-and-navigation code hangs or misses navigation | The navigation wait was registered after the click, or the click does not cause navigation. | Register the wait first with Promise.all(). If the interaction updates the page without navigation, wait for the resulting selector or state instead. |
| The script never finishes | A timeout was disabled with 0, or the wait condition is not going to occur. |
Restore a finite timeout and inspect the condition. Reserve an unbounded wait for cases where indefinite waiting is explicitly desired. |
The wait resolves with null |
A hidden selector wait can resolve successfully when the selector is not found. | For hidden: true, treat null as the expected hidden outcome; use a presence or visible-state wait if the next step needs the element. |
Performance, reliability, and cost
A longer timeout changes how long the script is willing to wait; it does not make the page load faster. Prefer waiting for the smallest meaningful condition instead of adding arbitrary delays. A selector wait is usually more specific than sleeping for a fixed duration because it can resolve as soon as the condition is met. Set a finite timeout so a missing condition fails in bounded time, and use navigation waits only for actions that actually navigate.
For a batch job, handle a timeout at the individual operation or page level so one slow page does not silently stall the whole run. Log the operation, URL, selector or navigation step, and configured timeout to make failures diagnosable. Puppeteer timeout settings do not themselves set a monetary price; runtime and infrastructure costs depend on how the surrounding automation is run.
Or skip the browser setup
If your goal is to get a page screenshot rather than automate a browser wait, ScreenshotNeo provides a screenshot API and MCP server. One GET request returns an image or PDF; its API documentation covers the available parameters.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
- Cookie banners, newsletter popups, and chat widgets are removed before the shot; each cleanup step can be turned off.
- Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed. Response headers say the page verdict and whether the shot was billed.
- An MCP server lets AI agents use
take_screenshot,get_page_info, andcapture_pdf. - The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is on every plan.
Sign up for 1,000 free screenshots a month, with no card.
FAQ
Does Puppeteer use seconds or milliseconds?
Milliseconds. Use 10_000 for ten seconds.
Will setDefaultTimeout() change every Puppeteer timeout?
No. It sets the page’s general default for applicable operations. Navigation has a separate default setting, and locator actions can have their own timeout.
Should I set the timeout to zero to fix timeouts?
Only if an indefinite wait is what you intend. Otherwise, keep a finite limit and fix the condition or scope that is timing out.
Can I make one selector wait longer without changing the page?
Yes. Pass { timeout: milliseconds } to that call’s options.


