Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Use driver.switch_to.window(handle) to move Selenium’s commands to an existing tab or window. Read the available handles from driver.window_handles, wait until a click has created a new handle, select the handle that was not present before the click, and then switch to it.

If your script needs to create a new top-level context itself, Selenium also provides driver.switch_to.new_window("tab") and driver.switch_to.new_window("window"). These create the context and switch to it in one operation.

What Selenium is switching

WebDriver commands run in the browsing context currently selected for the session. A browser can show several tabs or windows, but Selenium sends commands to only one selected context at a time. Switching this context is different from focusing an input element: driver.switch_to.active_element concerns the element focused inside the current document, while driver.switch_to.window(...) selects a tab or window.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Each open context has a session-specific handle. The handle is an opaque value; do not infer its meaning or assume that the second item in driver.window_handles is always the newly opened tab.

Switch to a tab opened by a page action

The reliable sequence is to save the current handle collection, perform the click or other action, wait for Selenium to observe a larger collection, find the handle that was not in the saved collection, and switch to it.

Complete Python example

from selenium import webdriver
from selenium.common.exceptions import TimeoutException, NoSuchWindowException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


driver = webdriver.Chrome()
wait = WebDriverWait(driver, 10)

try:
    driver.get("https://example.com")

    original_handle = driver.current_window_handle
    old_handles = driver.window_handles

    # Replace this locator with the control that opens the tab or window.
    driver.find_element(By.CSS_SELECTOR, "a.opens-new-window").click()

    # Wait until the number of window handles increases.
    wait.until(EC.new_window_is_opened(old_handles))

    # Select the handle that did not exist before the click.
    new_handle = next(
        handle for handle in driver.window_handles
        if handle not in old_handles
    )
    driver.switch_to.window(new_handle)

    # Commands now target the new tab or window.
    print(driver.title)

    # Return to the original context when needed.
    driver.switch_to.window(original_handle)
    print(driver.current_url)

except (TimeoutException, NoSuchWindowException) as exc:
    print(f"Could not switch browsing context: {exc}")
finally:
    driver.quit()

EC.new_window_is_opened(old_handles) receives the handles that existed before the action. It waits for the session’s handle count to increase, avoiding a race in which the click returns before the browser has registered the new context. The next(...) expression then chooses the newly observed handle without relying on ordering.

Why save both handles

  • driver.current_window_handle identifies the context selected before the action, so you can return to it explicitly.
  • driver.window_handles is the baseline used to detect what the page added.
  • Comparing the old and current collections is safer than using an index such as driver.window_handles[1].

Returning to the original tab

Keep the original handle in a variable before switching. After interacting with the new context, call driver.switch_to.window(original_handle). If the original context has been closed, that handle is no longer valid and you must select one that remains open.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Create and switch to a new context from Python

When the test itself—not the page—needs another context, use Selenium’s new_window method:

from selenium import webdriver

driver = webdriver.Chrome()
try:
    driver.get("https://example.com")

    driver.switch_to.new_window("tab")
    driver.get("https://example.org")
    print(driver.title)

    driver.switch_to.new_window("window")
    driver.get("https://www.python.org")
    print(driver.title)
finally:
    driver.quit()

The type hint can be "tab" or "window". If it is omitted, the browser chooses the type. This method creates a top-level browsing context and selects it; it is not a replacement for discovering a context that a page has already opened.

Use the returned current handle when you need to come back

After new_window, read driver.current_window_handle and save it if later code must return to that newly created context. You can also inspect driver.window_handles at any point to see the contexts still attached to the session.

Window names, handles and errors

Prefer handles from the current session

switch_to.window accepts a window name or a handle. Selenium first attempts to match the supplied value as a handle; if that fails, it checks the session’s windows for a matching window.name. If neither matches, it restores the original handle and raises NoSuchWindowException. Handles captured from driver.window_handles are the predictable choice because they identify contexts in the current WebDriver session.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A missing handle is not a missing element

NoSuchWindowException means the target browsing context cannot be selected. It is different from an element lookup error. Typical causes are a typo, a handle from a previous session, or code that closed the target before switching.

Closing one context versus ending the session

driver.close() closes the currently selected tab or window. driver.quit() ends the WebDriver session and closes all contexts managed by it. After close(), switch to a handle that still exists before issuing more page commands. A safe cleanup pattern is:

remaining = [h for h in driver.window_handles if h != driver.current_window_handle]
driver.close()
if remaining:
    driver.switch_to.window(remaining[0])
else:
    driver.quit()

In most test suites, putting driver.quit() in a finally block is simpler because it guarantees session cleanup even when a switch fails.

Choosing the right workflow

Situation Use Wait required? Handle practice
A link, button or script opens another context Save old handles, trigger the action, wait with new_window_is_opened, compare collections, then call switch_to.window(new_handle) Yes, because opening is asynchronous Save the original handle if you will return
The test must open a blank context switch_to.new_window("tab") or switch_to.new_window("window") No separate new-window wait Read and store current_window_handle after creation when needed
The page reused the current tab Continue in the current context; no window switch is needed Wait for the navigation or target element instead Do not assume every click creates a handle

Troubleshooting window-switch failures

The wait times out

  • Cause: the action opened the URL in the same tab, was prevented, or did not run.
  • Fix: verify the locator and click, inspect driver.window_handles before and after the action, and confirm that the expected behavior is a new top-level context rather than same-tab navigation.

The script switches to the wrong tab

  • Cause: code selected a numeric index or assumed handle ordering.
  • Fix: retain the pre-action collection and select the handle present afterward but absent beforehand. If more than one context can open, identify each new handle by a page-level condition such as title, URL, or a unique element after switching.

NoSuchWindowException appears after a successful click

  • Cause: the target was closed, the stored value came from another WebDriver session, or the switch ran before the context was available.
  • Fix: wait for the new handle, ensure the value came from the same driver instance, and check the current handle list immediately before switching.

The original tab cannot be restored

  • Cause: it was closed with close() or the session ended.
  • Fix: do not close the original context until the workflow is finished, or choose a surviving handle from driver.window_handles.

The click returns before the new page is usable

There are two separate events: creation of a browsing context and readiness of content inside it. First wait for the new handle, switch to it, then wait for the element or page condition your test actually needs. Increasing a fixed sleep is less reliable than waiting for those conditions.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance and reliability practices

  • Use one explicit WebDriverWait with a timeout appropriate for your environment instead of an arbitrary time.sleep.
  • Capture the baseline handles immediately before the action; collecting them much earlier can make an unrelated context look new.
  • Keep switching logic close to the action that creates the context so the baseline and comparison remain understandable.
  • Use descriptive variables such as original_handle, old_handles and new_handle; handle values themselves are not meaningful identifiers for your application.
  • Always terminate the driver in cleanup code. A leaked session can leave extra browser processes and make later tests harder to diagnose.

The Selenium Python API documentation currently labels the switch-to and WebDriver API as Selenium 4.49.0. The documented expected-condition result for new_window_is_opened is identified as Selenium 4.33.0; check the API version installed in your project when behavior or availability matters.

Or skip the browser setup

If your actual goal is to obtain a clean screenshot rather than test interactive window behavior, ScreenshotNeo returns an image or PDF from one request. It accepts 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, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and the response identifies the page verdict and billing status in headers.

See the ScreenshotNeo API documentation for the full options. A minimal cURL request is:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

The same request in Python:

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)

And in 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}`);

ScreenshotNeo also provides an MCP server with take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients. The Free plan includes 1,000 screenshots each month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Are window handles valid across separate WebDriver sessions?

No. A handle belongs to the session that returned it. Capture handles again whenever you create a new driver.

Can two tabs have the same URL and title?

Yes. URL and title are not guaranteed to identify a unique context; use the handle comparison technique and then inspect page content if you need to distinguish similar tabs.

What happens if no new handle appears after an action?

The action may have navigated the current tab, failed to open a context, or been blocked. Treat the unchanged handle list as evidence that there is no new context to switch to and debug the page action or wait condition.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.