Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
For a fixed delay in Pyppeteer, await a numeric page.waitFor() call. The value is milliseconds:
await page.waitFor(1000) # wait for 1 second
This pauses for one second, but it does not prove that a page, element, or network request is ready. For reliable automation, wait for the condition your next step actually needs.
What a numeric page.waitFor() value means
Pyppeteer’s 0.0.25 API reference treats a numeric selectorOrFunctionOrTimeout argument as a delay in milliseconds. Therefore, await page.waitFor(1000) requests a 1,000-millisecond pause. The method is asynchronous, so omitting await will not pause the coroutine as intended. See the Pyppeteer API reference.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
A fixed sleep is useful when you deliberately need to give an animation, debounce, or short client-side task time to run. It is a poor substitute for a readiness check: a fast page wastes time, while a slow page can still be unfinished when the delay ends.
#1 Best Overall
Common delay values
| Code | Requested pause | Use |
|---|---|---|
await page.waitFor(250) |
250 milliseconds | Short visual or debounce pause |
await page.waitFor(1000) |
1 second | Simple fixed delay |
await page.waitFor(5000) |
5 seconds | Only when a known operation needs a bounded pause |
The 1,000-millisecond example is an example value, not a Pyppeteer default or performance guarantee.
Use a condition instead of guessing a delay
When the purpose of the wait is “continue when something is ready,” use a condition-based method. These waits resolve immediately if the condition is already satisfied and otherwise keep polling until success or timeout.
Wait for a CSS selector
heading = await page.waitForSelector('h1', {'timeout': 5000})
waitForSelector() waits for DOM presence by default. Set visible=True when the matching node must be visible, or hidden=True when you need it to become hidden or absent:
Crashes, 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 minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallawait page.waitForSelector('#results', visible=True, timeout=10000)
await page.waitForSelector('.loading', hidden=True, timeout=10000)
Pyppeteer documentation supports an options dictionary and, depending on the installed version and call style, keyword arguments such as timeout=5000. Verify the signature in your installed package if one form raises a TypeError.
Rank #2
Wait for XPath
items = await page.waitForXPath('//ul[@id="results"]/li', {'timeout': 5000})
Use waitForXPath() when XPath expresses the target more clearly than a CSS selector.
Wait for a page condition
await page.waitForFunction('document.readyState === "complete"', {'timeout': 10000})
waitForFunction() evaluates a page function until it returns a truthy value. The documented polling choices include raf, mutation, or a numeric interval in milliseconds. A condition can be more meaningful than a sleep, but it can still time out if the condition never becomes true.
Timeout limits, units, and defaults
Do not confuse a delay with a timeout limit. In page.waitFor(1000), 1,000 milliseconds is the work you are asking Pyppeteer to perform. In waitForSelector('h1', {'timeout': 1000}), 1,000 milliseconds is the maximum time allowed for the selector to appear.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →The Pyppeteer 0.0.25 API reference documents a 30-second default (30,000 milliseconds) for waitForSelector(), waitForXPath(), waitForFunction(), waitForRequest(), and waitForResponse(). It documents the same 30-second default for navigation methods such as goto() and waitForNavigation(). Passing 0 disables the relevant timeout. These values come from documentation dated 2018, not a promise that every newer or modified package behaves identically.
For navigation methods, setDefaultNavigationTimeout() changes the default used by navigation operations. Prefer an explicit timeout on a critical wait when the limit should be visible at the call site.
A complete Pyppeteer example
The following script follows the project’s documented launch, page creation, navigation, and shutdown pattern. Pyppeteer may download Chromium the first time it runs if a compatible browser is not already available; the project README explains that behavior at the Pyppeteer repository.
import asyncio
from pyppeteer import launch
async def main():
browser = await launch()
try:
page = await browser.newPage()
await page.goto('https://example.com')
# Wait for the content the next step needs, with a five-second limit.
heading = await page.waitForSelector('h1', {'timeout': 5000})
text = await page.evaluate('(element) => element.textContent', heading)
print(text)
finally:
await browser.close()
asyncio.get_event_loop().run_until_complete(main())
This script uses a five-second condition timeout, not a five-second sleep. If the h1 never appears, Pyppeteer raises a timeout exception and the finally block still closes the browser.
Recommended Free Tools
Waiting for navigation without a race
If a click or other action is expected to navigate, start the navigation wait and the action together. Starting waitForNavigation() separately can miss the navigation event, according to the API reference.
await asyncio.gather(
page.waitForNavigation(),
page.click('a.next'),
)
Add a selector or function wait after navigation when the destination renders important content asynchronously:
await asyncio.gather(
page.waitForNavigation({'timeout': 30000}),
page.click('a.next'),
)
await page.waitForSelector('#article', {'timeout': 10000})
Choosing the right wait
| Need | Use | What it proves |
|---|---|---|
| Pause for a known interval | await page.waitFor(milliseconds) |
Only that the requested time elapsed |
| Element exists in the DOM | waitForSelector(selector) |
A matching node is present |
| Element is visible | waitForSelector(selector, visible=True) |
The matching node meets Pyppeteer’s visibility check |
| Element disappears | waitForSelector(selector, hidden=True) |
The node is hidden or absent |
| XPath target appears | waitForXPath(xpath) |
An XPath match is available |
| Arbitrary browser state | waitForFunction(expression) |
Your expression returns a truthy value |
| Action changes the document | asyncio.gather(waitForNavigation(), action) |
The navigation event and triggering action are coordinated |
Troubleshooting timeout problems
“The page still is not ready after waitFor()”
Replace the fixed delay with a selector or function that represents readiness. For example, wait for #results rather than sleeping for an arbitrary number of seconds. If the page can legitimately take longer, increase that condition’s timeout instead of repeatedly adding sleeps.
“Timeout waiting for selector”
- Confirm the selector is correct and matches the page actually loaded.
- Check whether the content is inside an iframe; a selector on the top-level page will not find nodes in a different frame.
- Determine whether the element is inserted only after a click, API response, or consent interaction, and perform that prerequisite first.
- Use
visible=Trueonly when visibility is required; the default checks DOM presence. - Temporarily choose a longer explicit timeout to distinguish a slow page from an incorrect condition.
“The navigation wait hangs or misses the page change”
Coordinate the wait and the action with asyncio.gather(). Also verify that the action really triggers a document navigation; single-page applications may update the DOM without firing a traditional navigation event, in which case wait for a route-specific selector or function condition.
“My timeout setting is ignored”
Check whether you supplied an options dictionary or keyword arguments supported by your installed Pyppeteer version. Remember that a timeout option limits a condition; it does not create a delay. A numeric argument to page.waitFor() is the delay itself.
Best Value
“The browser fails before any wait runs”
Make sure Chromium can be downloaded or that launch() points to an installed executable. The project’s README and documentation landing page at pyppeteer.github.io/pyppeteer describe the project and its version history.
Reliability and performance practices
- Prefer the narrowest condition that proves the next operation is safe.
- Set explicit per-step limits so a failed page does not consume an unbounded amount of runtime.
- Keep navigation waits and their triggering actions together to avoid event races.
- Use a fixed delay only for a deliberate pause, such as allowing a known animation or debounce to finish.
- Close the browser in a
finallyblock so timeout exceptions do not leave Chromium processes running. - Log which wait failed and the URL being processed; this separates selector mistakes from slow or unavailable pages.
Version caveat: Pyppeteer is not current Puppeteer
The cited API reference is for Pyppeteer 0.0.25, with documentation history dated 2018-09-27. Pyppeteer describes itself as an unofficial Python port of Puppeteer and notes that JavaScript/Python differences can affect the API. Current Puppeteer documentation is useful upstream context, but it is not proof that every modern method or behavior exists in Pyppeteer. Check the installed package’s signatures and exception behavior when version-specific correctness matters. The current upstream Page API is available at github.com/puppeteer/puppeteer.
Or skip the browser setup
If your goal is simply to obtain a page image or PDF rather than interact with a browser, ScreenshotNeo provides a website screenshot API and MCP server. It handles consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses identify 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.
Free tools Windows power users keep installed
One-click scans. No signup required.
One GET request returns PNG, JPEG, WebP, or PDF. The API supports full-page lazy-image loading, CSS-selector element capture, dark mode, device presets and custom viewports, retina scale, PDF paper and page options, custom CSS and JavaScript, clicks, selector hiding, waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, TTL caching, signed image links, asynchronous jobs, webhooks, bulk capture of up to 100 URLs per call, usage data, and an OpenAPI specification.
Using the documented request format:
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 parameters and response handling. The same request in Python is:
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}`);
The Free plan includes 1,000 shots per month with no card. Paid plans are Starter $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000; yearly billing gives two months free, and every feature is included on every plan. Create a free ScreenshotNeo account to start.
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.

