Some workflows open new browser windows or tabs — clicking a “Terms and Conditions” link that opens in a new tab, OAuth login flows that open a popup, or print previews that launch a separate window. Selenium can only interact with one window at a time, so you must explicitly switch between window handles to interact with content in different windows. Managing these handles correctly is essential for testing any multi-window workflow.
Window Handles — Opening, Switching and Closing Windows
Every browser window or tab has a unique handle — a string identifier that Selenium uses to track and switch between windows. The driver always has one “current” window; all commands apply to that window until you switch.
from selenium import webdriver
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()
# ── Basic window handle management ──
def demonstrate_window_handles(driver):
# Get the current (original) window handle
original_window = driver.current_window_handle
print(f"Original window: {original_window}")
print(f"Total windows: {len(driver.window_handles)}")
# Click a link that opens a new tab/window
driver.find_element(By.CSS_SELECTOR, "a[target='_blank']").click()
# Wait for the new window to appear
WebDriverWait(driver, 10).until(EC.number_of_windows_to_be(2))
# Get all window handles
all_windows = driver.window_handles
print(f"After click — total windows: {len(all_windows)}")
# Switch to the new window (the one that is NOT the original)
for handle in all_windows:
if handle != original_window:
driver.switch_to.window(handle)
break
# Now interacting with the NEW window
print(f"New window title: {driver.title}")
print(f"New window URL: {driver.current_url}")
# Interact with elements in the new window
# ... driver.find_element(...) ...
# Close the new window
driver.close()
# Switch back to the original window
driver.switch_to.window(original_window)
print(f"Back to original: {driver.title}")
# ── Open a new window or tab programmatically (Selenium 4) ──
def open_new_window_selenium4(driver):
original = driver.current_window_handle
# Open a new tab
driver.switch_to.new_window("tab")
driver.get("https://www.example.com")
print(f"New tab: {driver.title}")
# Open a new window (separate browser window)
driver.switch_to.new_window("window")
driver.get("https://www.google.com")
print(f"New window: {driver.title}")
# Clean up: close extras and return to original
for handle in driver.window_handles:
if handle != original:
driver.switch_to.window(handle)
driver.close()
driver.switch_to.window(original)
# ── OAuth popup workflow ──
def handle_oauth_popup(driver):
original = driver.current_window_handle
# Click "Login with Google" — opens OAuth popup
driver.find_element(By.CSS_SELECTOR, "[data-testid='google-login']").click()
# Wait for popup
WebDriverWait(driver, 10).until(EC.number_of_windows_to_be(2))
# Switch to popup
popup = [h for h in driver.window_handles if h != original][0]
driver.switch_to.window(popup)
# Interact with OAuth form in the popup
driver.find_element(By.ID, "identifierId").send_keys("test@gmail.com")
driver.find_element(By.CSS_SELECTOR, "[data-testid='next-btn']").click()
# After OAuth completes, popup closes automatically
WebDriverWait(driver, 15).until(EC.number_of_windows_to_be(1))
# Switch back to original window
driver.switch_to.window(original)
# Verify login succeeded on the original page
WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, ".user-avatar"))
)
# ── Window management reference ──
WINDOW_COMMANDS = [
("driver.current_window_handle", "Get the active window's handle"),
("driver.window_handles", "Get list of all open window handles"),
("driver.switch_to.window(handle)", "Switch to a specific window"),
("driver.switch_to.new_window('tab')", "Open and switch to a new tab (Selenium 4)"),
("driver.switch_to.new_window('window')", "Open and switch to a new window (Selenium 4)"),
("driver.close()", "Close the CURRENT window only"),
("driver.quit()", "Close ALL windows and end the session"),
]
print("Window Management Reference")
print("=" * 65)
for cmd, desc in WINDOW_COMMANDS:
print(f" {cmd}")
print(f" → {desc}")
driver.close() and driver.quit() are fundamentally different. close() closes only the current window — if other windows are open, the session continues. quit() closes all windows and terminates the WebDriver session entirely. After calling close(), you must switch to another window handle; after calling quit(), any further driver commands will throw InvalidSessionIdException. In multi-window tests, use close() for popup cleanup and quit() only in teardown.window_handles is not guaranteed to be consistent across browsers. By saving the original handle first, you can reliably identify the new window as “the handle that is not the original” — regardless of order.driver.close(), the driver’s context becomes invalid — it is pointing to a window that no longer exists. You must immediately call driver.switch_to.window(some_handle) to switch to a valid window. Any find_element or navigation command between close() and switch_to.window() will throw NoSuchWindowException.Common Mistakes
Mistake 1 — Not waiting for the new window before switching
❌ Wrong: link.click(); driver.switch_to.window(driver.window_handles[1]) — the new window may not have opened yet, causing an IndexError.
✅ Correct: link.click(); WebDriverWait(driver, 10).until(EC.number_of_windows_to_be(2)); ... — wait for the window to exist before accessing its handle.
Mistake 2 — Using driver.quit() when only the popup should close
❌ Wrong: Calling driver.quit() to close a popup window — this kills the entire browser session including the main window.
✅ Correct: Switching to the popup, calling driver.close() (closes only the popup), then switching back to the original window.