     [Answers](https://scrapfly.io/blog)   /  [playwright](https://scrapfly.io/blog/tag/playwright)   /  [How to wait for page to load in Playwright?](https://scrapfly.io/blog/answers/how-to-wait-for-page-to-load-in-playwright)   # How to wait for page to load in Playwright?

 by [Bernardas Alisauskas](https://scrapfly.io/blog/author/bernardas) Oct 01, 2026 3 min read [\#playwright](https://scrapfly.io/blog/tag/playwright) [\#python](https://scrapfly.io/blog/tag/python) 

 [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fscrapfly.io%2Fblog%2Fanswers%2Fhow-to-wait-for-page-to-load-in-playwright "Share on LinkedIn") [  ](https://x.com/intent/tweet?url=https%3A%2F%2Fscrapfly.io%2Fblog%2Fanswers%2Fhow-to-wait-for-page-to-load-in-playwright&text=How%20to%20wait%20for%20page%20to%20load%20in%20Playwright%3F "Share on X") [  ](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fscrapfly.io%2Fblog%2Fanswers%2Fhow-to-wait-for-page-to-load-in-playwright "Share on Facebook")    

 

 

Summarize this article with

 [  ](https://chat.openai.com/?q=Summarize%20this%20article%20and%20explain%20how%20Scrapfly%20helps%20me%20scrape%20any%20website%20at%20scale%20and%20bypass%20anti-bot%20systems%20for%20my%20use%20case%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fanswers%2Fhow-to-wait-for-page-to-load-in-playwright) [  ](https://claude.ai/new?q=Summarize%20this%20article%20and%20explain%20how%20Scrapfly%20helps%20me%20scrape%20any%20website%20at%20scale%20and%20bypass%20anti-bot%20systems%20for%20my%20use%20case%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fanswers%2Fhow-to-wait-for-page-to-load-in-playwright) [  ](https://x.com/i/grok?text=Summarize%20this%20article%20and%20explain%20how%20Scrapfly%20helps%20me%20scrape%20any%20website%20at%20scale%20and%20bypass%20anti-bot%20systems%20for%20my%20use%20case%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fanswers%2Fhow-to-wait-for-page-to-load-in-playwright) [  ](https://www.perplexity.ai/search/new?q=Summarize%20this%20article%20and%20explain%20how%20Scrapfly%20helps%20me%20scrape%20any%20website%20at%20scale%20and%20bypass%20anti-bot%20systems%20for%20my%20use%20case%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fanswers%2Fhow-to-wait-for-page-to-load-in-playwright) [  ](https://www.google.com/search?udm=50&aep=11&q=Summarize%20this%20article%20and%20explain%20how%20Scrapfly%20helps%20me%20scrape%20any%20website%20at%20scale%20and%20bypass%20anti-bot%20systems%20for%20my%20use%20case%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fanswers%2Fhow-to-wait-for-page-to-load-in-playwright) 



A page can fire `load` before your data exists and keep fetching long after it's ready, so wait for proof the data is there, not for a timer. Examples use Python and Playwright 1.63.0.



## What Does Page Loaded Mean in Playwright?

A page is ready when the condition your next extraction step depends on is true. No lifecycle event defines that condition for every modern page.

| Layer | What Playwright can prove | What it does not prove |
|---|---|---|
| Navigation lifecycle | The response committed, the DOM parsed, or `load` fired | Target records arrived after JavaScript ran |
| Locator actionability | A matched element is ready for the action | The full collection or backend work completed |
| Data readiness | A chosen response, URL, Locator, count, or predicate became true | Unrelated resources or future lazy data finished |

The [Playwright navigation lifecycle](https://playwright.dev/python/docs/navigations) docs say it directly: modern pages keep fetching and mutating after `load`, so there is no single loaded state.

`page.goto()` waits for `load` by default. That is correct when dependent resources are the requirement. Use `wait_until="commit"` or `"domcontentloaded"` only when a later, more specific wait owns readiness.

Hydration adds one more gap. An element can appear before its event listeners are attached, so wait for the resulting state you need rather than treating visibility as proof the app is ready. For setup and parsing, see the [complete Playwright scraping guide](https://scrapfly.io/blog/posts/web-scraping-with-playwright-and-python).



## Which Playwright Wait Should You Use for Scraping?

Start from the evidence your scraper needs, then pick the API that observes it.

| Scraper needs proof that... | Use | Boundary |
|---|---|---|
| One required element exists or is visible | `Locator.wait_for()` | Proves only that Locator state |
| A click is safe | Locator action such as `click()` | Auto-waits for action checks |
| A route or redirect completed | `page.wait_for_url()` | Match the expected URL pattern |
| A data API responded | `page.expect_response()` | Start waiting before the trigger |
| JavaScript state meets a bounded rule | `page.wait_for_function()` | Keep the predicate narrow |
| Initial DOM parsed | `domcontentloaded` | Dynamic data may still be absent |
| Dependent resources loaded | `load` | Later fetches can still run |
| A fixed delay elapsed | `wait_for_timeout()` | Debugging only |

For scraping, prefer the narrowest signal tied to the fields you parse next. [Playwright auto-waiting and actionability](https://playwright.dev/python/docs/actionability) checks cover a single action on a single element. They say nothing about whether a result set is complete.

Python uses snake\_case names. In TypeScript the same waits are `locator.waitFor()`, `waitForURL()`, `waitForResponse()`, and `waitForFunction()`.



## How Do Playwright Locators Wait for Dynamic Content?

Wait on a Locator when that exact element is the readiness contract, such as the first result card. Use `Locator.wait_for()` instead of `page.wait_for_selector()`, which the Page API now marks as discouraged.

The reviews on `web-scraping.dev/reviews` render after page load, so reading the DOM at `commit` finds none:

python

```python
from playwright.sync_api import sync_playwright

with sync_playwright() as pw:
    browser = pw.chromium.launch()
    page = browser.new_page()
    page.goto("https://web-scraping.dev/reviews", wait_until="commit")

    reviews = page.locator('[data-testid="review"]')
    # wait until at least one review is rendered
    reviews.first.wait_for(state="visible")

    # all() does not wait, so call it only after the wait above
    for review in reviews.all():
        print(review.locator('[data-testid="review-text"]').inner_text())
    browser.close()
```



The first visible row proves at least one row exists. It does not prove pagination, lazy loading, or the final count is complete. `Locator.all()` returns whatever matches at that moment, so always wait before calling it.

This pattern fits jobs that need the available rows, not an exhaustive final dataset. Waiting for a loading spinner to become hidden also works, but only when the target app reliably owns that spinner.



## How Do You Wait for a Playwright Response, URL, or App State?

Use `page.expect_response()` when a specific XHR or fetch response carries the records, `page.wait_for_url()` when navigation is the state change, and `page.wait_for_function()` for a bounded app condition.

The reviews page loads its data from `/api/graphql`. Register the response wait before the navigation that triggers it, otherwise the response can arrive before Playwright starts listening:

python

```python
from playwright.sync_api import sync_playwright

with sync_playwright() as pw:
    browser = pw.chromium.launch()
    page = browser.new_page()

    # register the wait before the action that triggers the request
    with page.expect_response(
        lambda response: "/api/graphql" in response.url and response.ok
    ) as response_info:
        page.goto("https://web-scraping.dev/reviews", wait_until="commit")
    print(response_info.value.status, response_info.value.url)

    reviews = page.locator('[data-testid="review"]')
    reviews.first.wait_for(state="visible")
    for review in reviews.all():
        print(review.locator('[data-testid="review-text"]').inner_text())
    browser.close()
```



The response proves the data arrived and the Locator proves it rendered. Some flows need both checks. A single response still doesn't prove every page of records loaded. To find the right request, [inspect Playwright XHR and fetch traffic](https://scrapfly.io/blog/answers/how-to-capture-xhr-requests-playwright).

When a click changes the route, wait for the expected URL rather than any URL change:

python

```python
from playwright.sync_api import sync_playwright

with sync_playwright() as pw:
    browser = pw.chromium.launch()
    page = browser.new_page()
    page.goto("https://web-scraping.dev/products")
    page.locator("h3.mb-0 a").first.click()
    page.wait_for_url("**/product/1")
    print(page.url)
    browser.close()
```



For state the DOM doesn't expose cleanly, pass `page.wait_for_function()` a narrow JavaScript predicate, such as an app flag or a minimum known count. A count that stays stable for a moment is not proof that all content is loaded.



Scrapfly

#### Need a cloud browser for scraping?

Run headless browsers at scale with Scrapfly Cloud Browser — no infrastructure to manage.

[Try Free →](https://scrapfly.io/register)## Why Does Playwright networkidle Time Out or Return Too Early?

`networkidle` fires once the page has had no network connections for at least 500 ms. If that already happened before you call it, the wait returns immediately. It is a quiet window, not a completeness signal, and the [Page API](https://playwright.dev/python/docs/api/class-page#page-wait-for-load-state) marks it discouraged for readiness checks.

It fails in both directions:

- Polling, analytics, streaming, or other long-lived traffic can prevent the quiet window, so the wait runs to its timeout.
- Called right after a click, it can resolve immediately, before the navigation or request that click triggered has started.

A [r/Playwright user reported](https://www.reddit.com/r/Playwright/comments/1p5xlis/what_does_waitforloadstatenetworkidle_wait_for/) this second shape in a trace: `networkidle` resolved in `0ms`, and the next load began `100-200ms` later. Treat it as an observed symptom, not proof of Playwright internals.

Network quiet also isn't visual stability. In a [Stack Overflow question](https://stackoverflow.com/questions/71937343/playwright-how-to-wait-until-there-is-no-animation-on-the-page), `networkidle` didn't reliably mean a JavaScript-heavy page had stopped animating, so the author compared screenshots taken 100 ms apart. If you need visual stability, define it as its own bounded condition.

`networkidle` can still work on simple pages. As a default, wait for the target response, Locator, URL, or app predicate instead.



## How Do You Fix a Playwright TimeoutError?

Read the failing operation and its call log, find the condition that never became true, and fix that condition before touching the timeout.

| Failure | Inspect first | Typical correction |
|---|---|---|
| `page.goto()` timeout | Requested lifecycle state, redirects, slow dependencies | Use the boundary the next step needs |
| Locator timeout | Selector, frame, visibility state | Fix the Locator or expected state |
| Action timeout | Actionability log | Resolve visibility, stability, enabled state, or an overlay |
| Response timeout | Predicate and trigger order | Register before the action, narrow the predicate |
| URL timeout | Expected route pattern | Match the real redirect or client-side route |
| Function timeout | Predicate evidence | Simplify it and inspect the live value |

These waits default to 30,000 ms unless page or context timeout settings change it. Playwright Test assertion timeouts are a separate system.

A longer, scoped timeout is valid when the condition is correct, the target is predictably slow, and the upper bound is intentional. For example, `wait_for(timeout=60_000)` on a Locator you know is right. It won't help with a wrong selector, a wrong frame, a response wait registered after its trigger, or a global condition unrelated to the data you need.



## FAQ

What Is the Default Playwright Timeout?`page.expect_response()`, `page.wait_for_url()`, `page.wait_for_function()`, and `Locator.wait_for()` default to 30,000 ms unless page or browser-context timeout settings change it. This is separate from the Playwright Test timeout system.







How Do You Wait After Clicking in Playwright?Wait for the condition the click causes: `wait_for_url()` for navigation, `expect_response()` for a data request, or a Locator for the resulting UI. Register a response expectation before the click, because the response can arrive immediately.







Can Playwright Wait for Five Seconds?Yes, `page.wait_for_timeout(5000)` pauses for five seconds, but Playwright documents it for debugging. In production it either expires before the data arrives or delays a page that was ready sooner.







Does Playwright Auto-Wait Until the Whole Page Loads?No. Auto-waiting runs the checks one action needs on one element. It doesn't know whether all scrape data, pagination, or background work is complete.







Choose a Playwright Readiness Signal, Not a Longer SleepChoose the smallest observable condition that proves your next extraction step can run. Local Playwright is fine while running browsers is manageable. If browser infrastructure becomes the bottleneck, [Scrapfly Cloud Browser](https://scrapfly.io/products/cloud-browser-api) accepts Playwright over CDP, so your Locator, response, URL, and function waits stay in client code. For one-shot rendered fetches, [Web Scraping API JavaScript rendering](https://scrapfly.io/docs/scrape-api/javascript-rendering) can wait for a CSS or XPath selector, or an `xhr:` URL pattern, without a long-running session.









[Web Scraping With Playwright in 2026: A Python GuideScrape JavaScript-rendered pages with Playwright and Python in 2026: locators, waiting, request interception, resource blocking, and concurrency.](https://scrapfly.io/blog/posts/web-scraping-with-playwright-and-python)



 

   [  Add as a preferred source ](https://google.com/preferences/source?q=scrapfly.io) Table of Contents















 

  Table of Contents

- [What Does Page Loaded Mean in Playwright?](#what-does-page-loaded-mean-in-playwright)
- [Which Playwright Wait Should You Use for Scraping?](#which-playwright-wait-should-you-use-for-scraping)
- [How Do Playwright Locators Wait for Dynamic Content?](#how-do-playwright-locators-wait-for-dynamic-content)
- [How Do You Wait for a Playwright Response, URL, or App State?](#how-do-you-wait-for-a-playwright-response-url-or-app-state)
- [Why Does Playwright networkidle Time Out or Return Too Early?](#why-does-playwright-networkidle-time-out-or-return-too-early)
- [How Do You Fix a Playwright TimeoutError?](#how-do-you-fix-a-playwright-timeouterror)
- [FAQ](#faq)
 
    Join the Newsletter  Get monthly web scraping insights 

 

  



Scale Your Web Scraping

Anti-bot bypass, browser rendering, and rotating proxies, all in one API. Start with 1,000 free credits.

  No credit card required  1,000 free API credits  Anti-bot bypass included 

 [Start Free](https://scrapfly.io/register) [View Docs](https://scrapfly.io/docs/onboarding) 

 Not ready? Get our newsletter instead. 

 

 ## Related Articles

 [     

 python hidden-api 

### How to Scrape Google Play App Reviews and Data

Scrape Google Play app metadata, ratings, and the full review set with Python, past the few-hundred-review ceiling the f...

 

 ](https://scrapfly.io/blog/posts/how-to-scrape-google-play-app-reviews-and-data) [  

 python crawling 

### Guide to List Crawling: Everything You Need to Know

Complete list crawling tutorial assess site defenses, bypass anti-bot systems, choose tools (Beautiful Soup, Playwright,...

 

 ](https://scrapfly.io/blog/posts/guide-to-list-crawling) [     

 python headless-browser 

### How to Scrape Infinite Scroll, Load More &amp; Paginated Pages

Learn to scrape infinite scroll, load more, and paginated pages in 2026 by reverse-engineering the request first and usi...

 

 ](https://scrapfly.io/blog/posts/how-to-scrape-infinite-scroll-load-more-and-paginated-pages) 

  ## Related Questions

- [ Q How to wait for a page to load in Puppeteer? ](https://scrapfly.io/blog/answers/how-to-wait-for-page-to-load-in-puppeteer)
- [ Q How to wait for page to load in Selenium? ](https://scrapfly.io/blog/answers/how-to-wait-for-page-to-load-in-selenium)
- [ Q How to load local files in Puppeteer? ](https://scrapfly.io/blog/answers/how-to-load-local-files-in-puppeteer)
- [ Q How to check if element exists in Playwright? ](https://scrapfly.io/blog/answers/how-to-check-for-element-in-playwright)
 
  



   



 Run headless browsers at scale, **1,000 free credits** [Start Free](https://scrapfly.io/register)