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.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →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.
#1 Best Overall
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_handleidentifies the context selected before the action, so you can return to it explicitly.driver.window_handlesis 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.
Rank #2
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.
Rank #3
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.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteA 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:
Rank #4
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_handlesbefore 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
driverinstance, 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.
Performance and reliability practices
- Use one explicit
WebDriverWaitwith a timeout appropriate for your environment instead of an arbitrarytime.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_handlesandnew_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.
Best Value
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.
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.
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.
Recommended Free Tools

