Skip to main content

Navigations

Playwright can navigate to URLs and handle navigations caused by page interactions. This guide covers common scenarios to wait for page navigations and loading to complete.

Playwright splits the process of showing a new document in a page into navigation and loading.

Navigation starts by changing the page URL or by interacting with the page (e.g., clicking a link). The navigation intent may be canceled, for example, on hitting an unresolved DNS address or transformed into a file download.

Navigation is committed when the response headers have been parsed and session history is updated. Only after the navigation succeeds (is committed), the page starts loading the document.

Loading covers getting the remaining response body over the network, parsing, executing the scripts and firing load events:

  • page.url is set to the new url
  • document content is loaded over network and parsed
  • page.on("domcontentloaded") event is fired
  • page executes some scripts and loads resources like stylesheets and images
  • page.on("load") event is fired
  • page executes dynamically loaded scripts
  • networkidle is fired when no new network requests are made for 500 ms

Scenarios initiated by browser UI

Navigations can be initiated by changing the URL bar, reloading the page or going back or forward in session history.

Auto-wait

Navigating to a URL auto-waits for the page to fire the load event. If the page does a client-side redirect before load, page.goto(url, **kwargs) will auto-wait for the redirected page to fire the load event.

# Navigate the page
page.goto("https://example.com")

Custom wait

Override the default behavior to wait until a specific event, like networkidle.

# Navigate and wait until network is idle
page.goto("https://example.com", wait_until="networkidle")

Wait for element

In lazy-loaded pages, it can be useful to wait until an element is visible with locator.wait_for(**kwargs). Alternatively, page interactions like page.click(selector, **kwargs) auto-wait for elements.

# Navigate and wait for element
page.goto("https://example.com")
page.get_by_text("example domain").wait_for()

# Navigate and click element
# Click will auto-wait for the element
page.goto("https://example.com")
page.get_by_text("example domain").click()

Scenarios initiated by page interaction

In the scenarios below, locator.click(**kwargs) initiates a navigation and then waits for the navigation to complete.

Auto-wait

By default, locator.click(**kwargs) will wait for the navigation step to complete. This can be combined with a page interaction on the navigated page which would auto-wait for an element.

# Click will auto-wait for navigation to complete
page.get_by_text("Login").click()

# Fill will auto-wait for element on navigated page
page.get_by_label("User Name").fill("John Doe")

Custom wait

locator.click can be combined with page.wait_for_load_state(**kwargs) to wait for a loading event.

page.locator("button").click(); # Click triggers navigation
page.wait_for_load_state("networkidle"); # This waits for the "networkidle"

Wait for element

In lazy-loaded pages, it can be useful to wait until an element is visible with locator.wait_for(**kwargs). Alternatively, page interactions like locator.click(**kwargs) auto-wait for elements.

# Click triggers navigation
page.get_by_text("Login").click()
# Click will auto-wait for the element
page.get_by_label("User Name").wait_for()

# Click triggers navigation
page.get_by_text("Login").click()
# Fill will auto-wait for element
page.get_by_label("User Name").fill("John Doe")

Asynchronous navigation

Clicking an element could trigger asynchronous processing before initiating the navigation. In these cases, it is recommended to explicitly call page.expect_navigation(**kwargs). For example:

  • Navigation is triggered from a setTimeout
  • Page waits for network requests before navigation
# Waits for the next navigation. Using Python context manager
# prevents a race condition between clicking and waiting for a navigation.
with page.expect_navigation():
# Triggers a navigation after a timeout
page.locator("a").click()

Multiple navigations

Clicking an element could trigger multiple navigations. In these cases, it is recommended to explicitly page.expect_navigation(**kwargs) to a specific url. For example:

  • Client-side redirects issued after the load event
  • Multiple pushes to history state
# Using Python context manager prevents a race condition
# between clicking and waiting for a navigation.
with page.expect_navigation(url="**/login"):
# Triggers a navigation with a script redirect
page.get_by_text("Click me").click()

Loading a popup

When popup is opened, explicitly calling page.wait_for_load_state(**kwargs) ensures that popup is loaded to the desired state.

with page.expect_popup() as popup_info:
page.locator('a[target="_blank"]').click() # Opens popup
popup = popup_info.value
popup.wait_for_load_state("load")

Advanced patterns

For pages that have complicated loading patterns, page.wait_for_function(expression, **kwargs) is a powerful and extensible approach to define a custom wait criteria.

page.goto("http://example.com")
page.wait_for_function("() => window.amILoadedYet()")
# Ready to take a screenshot, according to the page itself.
page.screenshot()