ScreenshotNeo

BlogHow-to

How to Handle Multiple Windows in Selenium WebDriver with Java

Save the current window handle, wait for a new tab or window, switch to it, and return safely with Selenium WebDriver in Java.

By the ScreenshotNeo team4 October 20267 min read

To handle a tab or window opened by an application, save the current handle, trigger the action, wait for the handle set to change, find the new handle by comparing sets, and call driver.switchTo().window(handle). When finished, close the child context if appropriate and explicitly switch back to the saved handle. WebDriver does not automatically follow the browser’s visible focus.

This guide covers Selenium WebDriver with Java, including Selenium 4’s direct tab creation, multiple popups, safe cleanup, common failures, and the distinction between browser automation and capturing a page image.

1. Understand handles, tabs, and windows

WebDriver identifies each open browsing context with a window handle. The same handle model applies to tabs and separate browser windows.

  • driver.getWindowHandle() returns the handle for the context currently selected by WebDriver.
  • driver.getWindowHandles() returns the handles for all open contexts in the session.
  • driver.switchTo().window(handle) selects a context for subsequent WebDriver commands.

A page action can open a tab while WebDriver remains scoped to the original tab. Always switch explicitly before reading its title, locating elements, or interacting with it. See Selenium’s official guide to working with windows and tabs and the Java API references for getWindowHandles and switchTo().window.

2. Switch to a window opened by the application

This example waits for a new handle instead of guessing when the browser will create it. It compares against the complete pre-action set, so it works even if the test already had more than one context open.

import java.time.Duration;
import java.util.Set;

import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchWindowException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.WebDriverWait;

// Assumes driver has already been created and navigated to the page.
String originalHandle = driver.getWindowHandle();
Set<String> handlesBefore = driver.getWindowHandles();

// Trigger the application action that opens a tab or window.
driver.findElement(By.linkText("Open new window")).click();

WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
wait.until(d -> d.getWindowHandles().size() > handlesBefore.size());

String newHandle = driver.getWindowHandles().stream()
    .filter(handle -> !handlesBefore.contains(handle))
    .findFirst()
    .orElseThrow(() -> new NoSuchWindowException("New window did not appear"));

driver.switchTo().window(newHandle);
wait.until(d -> !d.getTitle().isEmpty());

// Replace with an assertion appropriate to your test framework.
if (!driver.getTitle().contains("Expected page")) {
    throw new AssertionError("Unexpected title: " + driver.getTitle());
}

// Close the child, then explicitly return to the original context.
driver.close();
driver.switchTo().window(originalHandle);

The imports above cover the window-handling example. Your project also needs Selenium’s Java client and a compatible browser driver setup; use the dependency and driver-management approach already established by your project. The example uses Java’s Duration constructor for WebDriverWait. Check the official WebDriverWait Java reference if matching a different Selenium version.

Why compare handles instead of choosing the last one?

getWindowHandles() returns a set, not a contract that the popup will occupy a particular index. Save the original set, then select a handle that was not present before. The count increase is a useful wait condition; the set difference identifies the context to switch to.

Wait for the page, not just the context

A new handle means the context exists; it does not guarantee the page has finished loading or contains the target content. After switching, wait for a meaningful condition such as a known element, URL, or title. An empty-title check is only an example and may not be sufficient for every site.

3. Handle multiple existing contexts or several popups

If more than one new context appears, do not pick an arbitrary one. Iterate through the handles that were absent before the action, switch to each, and identify the intended page using a stable property such as its URL, title, or a page-specific element.

Set<String> handlesAfter = driver.getWindowHandles();

for (String handle : handlesAfter) {
    if (handlesBefore.contains(handle)) {
        continue;
    }

    driver.switchTo().window(handle);
    String url = driver.getCurrentUrl();
    String title = driver.getTitle();

    if (url.startsWith("https://example.com/confirmation")) {
        // This is the context the test needs.
        break;
    }
}

// Assert that the selected context is the intended one before continuing.

For robust production tests, record whether a match was found and fail with a useful message if none was. If the application can open multiple windows at once, decide what should happen to the extra contexts and close them deliberately.

4. Create a new tab or window with Selenium 4+

When the test itself needs a fresh browsing context, Selenium 4 and later provide newWindow. It creates and selects the new context directly.

import org.openqa.selenium.WindowType;

driver.switchTo().newWindow(WindowType.TAB);
driver.get("https://example.com");

// Or create a separate browser window:
driver.switchTo().newWindow(WindowType.WINDOW);
driver.get("https://example.com");

This is different from handling a context opened by the application. For an application-opened popup, wait for and discover its handle. For a test-created context, newWindow performs the creation and switch.

5. Close a child and return to the parent safely

driver.close() closes only the currently selected context. Save the parent handle before switching, close the child when finished, and switch back before issuing more commands. Selenium documents that commands issued while WebDriver remains on a closed context can raise NoSuchWindowException.

Use driver.quit() when the entire test session is over; it ends the session and closes its windows. Do not close the only remaining context and expect to keep using it.

6. Troubleshooting common failures

Symptom Likely cause Fix
No new handle is found immediately after clicking The browser has not created the popup yet, or the click did not open one. Wait for the handle count to increase. Check that the locator targets the expected control and that the application action succeeded.
The test keeps interacting with the original page WebDriver does not automatically switch when a tab appears or receives visual focus. Call switchTo().window(newHandle) before interacting with the new page.
The wrong popup is selected The code assumes handle order or assumes exactly one new context. Compare against the saved pre-action set; if several handles were added, inspect each page’s URL, title, or a distinguishing element.
NoSuchWindowException after closing a tab WebDriver is still selected on the context that was closed. Switch immediately to a handle that remains open. Keep the parent handle saved before opening the child.
The handle count never changes The action was blocked, opened in the same tab, failed validation, or the wait is observing the wrong session state. Verify the application behavior and popup policy in the test environment. If navigation occurs in the same tab, wait for a URL or page condition instead of a new handle.
The handle exists but the expected element is missing The new document is still loading, redirected, or differs from the expected page. After switching, use an explicit wait for the target element or expected URL, then report the observed URL and title on failure.
Compilation fails on newWindow or WindowType The project uses a Selenium version before Selenium 4, or lacks the relevant import. Use a Selenium 4+ dependency for newWindow, or use the handle-discovery workflow for contexts opened by the application.

7. Reliability, speed, and test design

  • Prefer explicit waits. A bounded wait for a handle or page condition adapts to variable load times better than a fixed sleep. Choose a timeout based on the application and test environment; the sample’s ten seconds is illustrative.
  • Keep context cleanup explicit. Close only contexts the test owns, and always leave WebDriver on a live handle before continuing.
  • Use semantic identification. URL, title, or page content is more reliable than set iteration order.
  • Keep tests isolated. Popups left open can affect later assertions and resource use. Close extra contexts or end the session with quit().
  • Use a same-tab wait when appropriate. Some links navigate the current context instead of opening another. In that case, wait for the new URL or target content rather than expecting an additional handle.

Window handling itself does not require repeated polling with arbitrary sleeps. Explicit waits check a condition until it becomes true or the timeout expires. Selenium’s WebDriverWait API documents the Java wait abstraction.

8. Or skip the browser setup

If your goal is a screenshot rather than testing interactions across browser contexts, ScreenshotNeo is a website screenshot API and MCP server for developers. One GET request captures a URL as PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);

ScreenshotNeo accepts cookie or consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before the shot; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.

Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.

9. Frequently asked questions

How do I switch back to the parent window after closing a popup?

Save the parent’s handle before opening the popup. After closing the selected child with close(), call switchTo().window(parentHandle).

Can I use the same code for tabs and separate windows?

Yes. Both are browsing contexts represented by handles, so discovery and switching use the same WebDriver methods.

Should I use close() or quit()?

Use close() for the selected tab or window. Use quit() to end the complete WebDriver session.

Can WebDriver switch to a tab opened outside the test?

WebDriver can switch only among contexts in its session. The tab must belong to that browser session and appear in getWindowHandles().