Explicit Wait in Selenium: Java and Python Examples
Learn with AI
X (Twitter)
Learn with AI
Explicit wait in Selenium pauses a test until one specific condition becomes true for one specific element, instead of waiting on a fixed timer.
Quick answer: Explicit wait = wait for a specific condition on a specific element, usually written as WebDriverWait + ExpectedConditions. It differs from implicit wait, which applies one blanket timeout to every element lookup in the session.
Most guides to explicit wait give you one WebDriverWait snippet and call it done. The snippet is the easy part. What actually decides whether your suite is stable is which condition you wait for, how explicit wait interacts with the implicit wait you may have set elsewhere, and whether your code still uses the pre-Selenium 4 syntax that quietly went stale a few years ago.
If a test clicks a button a fraction of a second before it is interactive and throws ElementNotInteractableException, you have met the problem explicit wait solves. It pauses your script until a specific condition is true, so you act on the page when it is ready rather than when the clock says so.
Here is what we will cover:
- What explicit wait actually is, and how it relates to WebDriverWait
- The real difference between implicit, explicit, and fluent waits
- What Selenium does with no wait configured at all, and how to check that baseline yourself
- Correct Selenium 4 examples in Java and Python
- The conditions you will actually use, and how to pick the right one
- What changed in Selenium 4, so your code is not stuck on deprecated syntax
- How to catch a TimeoutException without crashing your entire test
- The mistakes that make explicit waits flaky, and how Katalon Studio handles the same problem
What is explicit wait in Selenium?
Explicit wait pauses test execution until a specific condition is met or a timeout is reached, then continues as soon as the condition is true. Unlike an implicit wait, which applies one blanket timeout to every element lookup, an explicit wait targets a single condition on a single element, such as becoming visible, clickable, or present in the DOM.
In practice, you create an explicit wait with the WebDriverWait class and hand it an expected condition. So when people say "explicit wait," they almost always mean a WebDriverWait paired with an ExpectedConditions check. That is the tool you will reach for most often in real test code.
Implicit vs explicit vs fluent wait
Selenium gives you three wait types, and the most common cause of flaky timing is treating them as interchangeable. Here is how they actually differ.
| Wait type | Scope | What it does | Reach for it when |
|---|---|---|---|
| Implicit wait | Global, whole session | Sets a default poll time the driver applies to every findElement call before throwing NoSuchElementException | You want a simple baseline and nothing more. Set it once, then leave it alone. |
| Explicit wait | One element or condition | Waits for a specific ExpectedCondition (visible, clickable, text present) up to a timeout | You are waiting on a known condition for a known element. This is the default tool for most waits. |
| Fluent wait | One element or condition | An explicit wait with manual control over polling frequency and ignored exceptions | The defaults are not enough. You need a custom poll interval or to ignore a specific exception while polling. |
The short version: implicit wait handles general delays, explicit wait handles precise conditions, and fluent wait is explicit wait with the dials exposed. We go deep on the third one in the guide to Fluent Wait in Selenium.
Selenium's default timeout: what happens with no wait at all
Before you add any wait strategy, it helps to know what Selenium does on its own: nothing. Out of the box, Selenium checks for an element exactly once. If it is not there yet, Selenium throws NoSuchElementException immediately instead of giving the page a chance to catch up.
You can see this baseline directly by setting the implicit wait to zero. It is also the right way to confirm a test is not quietly inheriting a leftover implicit wait from earlier setup code.
import java.time.Duration;
driver.manage().timeouts().implicitlyWait(Duration.ZERO);
driver.implicitly_wait(0)
This is why explicit wait exists in the first place. Without it, and without an implicit wait set somewhere, every element lookup on a dynamic page is a race between your script and the browser, and the browser is not guaranteed to win.
Explicit wait syntax in Java
This is the current Selenium 4 setup. Note the Duration, which matters and is covered below.
import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
WebElement loginBtn = wait.until(
ExpectedConditions.elementToBeClickable(By.id("login"))
);
loginBtn.click();
The wait checks for the login button to become clickable, returns it the moment it is ready, and throws a TimeoutException if 10 seconds pass without it. You act on the element only when Selenium confirms the condition, not on a fixed guess.
Explicit wait in Python
The Python binding uses the same WebDriverWait class with the expected_conditions module, conventionally imported as EC.
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
wait = WebDriverWait(driver, timeout=10)
login_btn = wait.until(EC.element_to_be_clickable((By.ID, "login")))
login_btn.click()
Same behavior as the Java version. The locator is passed as a tuple, (By.ID, "login"), which is the Python convention that trips up people arriving from Java.
The conditions you will actually use
Explicit wait is only as good as the condition you give it, and most flaky waits come from picking the wrong one. These three are easy to confuse and behave differently.
- Presence (presenceOfElementLocated): the element exists in the DOM. It may be invisible or not yet interactive. Use it when you only need to confirm the element was rendered, for example before reading a hidden attribute.
- Visibility (visibilityOfElementLocated): the element is in the DOM and actually displayed, with a height and width greater than zero. Use it when you need to read visible text or confirm something appeared.
- Clickable (elementToBeClickable): the element is visible and enabled. Use it before any click. It sharply cuts down ElementNotInteractableException, though it is not a guarantee: an overlay or another element sitting on top can still intercept the click even after the condition passes.
Beyond those, the conditions you will reach for include textToBePresentInElementLocated, invisibilityOfElementLocated (handy for waiting out a loading spinner), alertIsPresent, frameToBeAvailableAndSwitchToIt, and titleContains. The Python module mirrors these with snake_case names such as text_to_be_present_in_element and invisibility_of_element_located.
The rule of thumb: wait for the state your next line actually needs. If you are about to click, wait for clickable, not presence.
What changed in Selenium 4
If you learned explicit wait a few years ago, your syntax is probably deprecated. Selenium 4 replaced the old (long, TimeUnit) timeout arguments with a single Duration, across implicit waits, WebDriverWait, and FluentWait. The old forms still compile for now but show deprecation warnings, and relying on them dates your code.
import java.time.Duration;
import java.util.concurrent.TimeUnit; // only needed for the deprecated example
import org.openqa.selenium.support.ui.WebDriverWait;
// Deprecated (pre-Selenium 4)
WebDriverWait wait = new WebDriverWait(driver, 10);
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
// Selenium 4 and later
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
Import java.time.Duration and the warnings go away. The same Duration change applies to withTimeout and pollingEvery on FluentWait. Selenium 4 also moved fully to the W3C WebDriver protocol under the hood, but for waits the Duration switch is the change you will actually touch.
Handling a TimeoutException in Selenium
Every explicit wait eventually fails on some run: a slow deploy, a flaky third-party script, a locator that stopped matching. When the condition never becomes true, WebDriverWait throws TimeoutException, and your test crashes right there unless you catch it.
Catching it on purpose, rather than letting the whole run die, gives you the chance to log what happened, capture evidence, or retry before giving up.
import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
try {
WebElement signupBtn = wait.until(
ExpectedConditions.elementToBeClickable(By.id("signup"))
);
signupBtn.click();
} catch (TimeoutException e) {
System.out.println("Signup button not found within timeout period");
}
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
wait = WebDriverWait(driver, timeout=10)
try:
wait.until(
EC.element_to_be_clickable((By.ID, "signup"))
).click()
except TimeoutException:
print("Signup button not found within timeout period")
Do not over-use this pattern. Catching TimeoutException to log context or retry once is reasonable; catching it just to swallow the error and continue hides a real failure instead of fixing it. If you are already building out failure evidence, our guide to taking screenshots in Selenium covers capturing the page at the exact moment a wait times out.
The mistakes that make explicit waits flaky
The syntax is rarely the problem. These are.
- Mixing implicit and explicit waits. The Selenium documentation warns against combining the two, because the timeouts can compound in ways that are hard to predict. A 10 second implicit wait plus a 10 second explicit wait does not reliably give you 10 seconds. Pick one model. If you use explicit waits, set your implicit wait to zero and leave it there.
- Waiting for the wrong condition. Waiting for presence and then clicking is the classic flaky pattern, because the element can be in the DOM long before it is interactive. Match the condition to the action.
- Timeouts so long they hide failures. A 60 second wait does not make a test more robust, it makes a genuine failure take a minute to surface. Set timeouts to the slowest realistic load, not the worst case you can imagine.
- Recreating the wait on every line. Build one WebDriverWait and reuse it, rather than constructing a new one before every interaction.
- Falling back to Thread.sleep(). It always waits the full duration even when the element was ready early, trading reliability for wasted time on every run. Treat it as a last resort, not a wait strategy.
Explicit wait or fluent wait?
Most of the time, explicit wait is the right call and its defaults are fine. Reach for fluent wait only when you need something the defaults will not give you: a custom polling interval, or the ability to ignore a specific exception such as StaleElementReferenceException while the page re-renders. Since WebDriverWait is itself a subclass of FluentWait in Java, you are not switching tools so much as exposing more dials on the same one. If your dynamic pages are fighting you, the Fluent Wait guide covers the polling and exception handling in full.
How Katalon Studio handles the same problem
Everything above is the manual approach, and for a small or highly custom suite that control is worth the code. The cost shows up at scale: you are choosing and maintaining the right condition and timeout around dynamic elements across hundreds of tests, and every one of those waits can drift or get copied slightly wrong.
Katalon Studio takes a different default. Its Smart Wait feature waits for the page to reach a static state, meaning pending AJAX calls, JavaScript, and resource loading have settled, before it performs the next action. Instead of you deciding element by element when the page is ready, "wait until the page actually stops changing" becomes the baseline for every step. It runs on Selenium 4.39 under the hood, so you keep the engine you already know, and it is on by default under Project > Settings > Execution > WebUI.
You can still be explicit when you want to. Studio's built-in keywords cover the common conditions without the boilerplate:
WebUI.waitForElementVisible(findTestObject('Page/btn_login'), 10)
WebUI.waitForElementClickable(findTestObject('Page/btn_login'), 10)
WebUI.waitForElementPresent(findTestObject('Page/result_row'), 10)
What Smart Wait removes is not waiting logic, it is the work of hand-picking and maintaining a condition and timeout for every dynamic element across a growing suite. You can still drop into explicit waits and Groovy whenever a custom condition demands it. When a wait does fail, Studio 11's Tracer records DOM snapshots, network activity, console logs, and browser state for the run, so a flaky failure leaves evidence behind instead of forcing you to guess.
If you hit an error from Katalon's own SmartWaitWebDriver rather than a plain Selenium timeout, see our guide to handling Selenium waits in Katalon for troubleshooting steps specific to that feature.
You can see it on a real page in the Smart Wait sample project, and the Smart Wait documentation covers the configuration in full.
|
FAQs on Selenium Explicit Wait
What are wait commands in Selenium?
They tell WebDriver to pause until a condition is met or a timeout finishes, helping tests align with actual UI behavior (not fixed delays like Thread.sleep()).
What’s the difference between implicit wait and explicit wait?
Implicit wait is a global timeout applied to all element lookups; explicit wait is targeted and pauses until a specific condition is met (like visibility or clickability).
What happens if no wait is configured in Selenium at all?
Selenium checks for an element exactly once and throws NoSuchElementException immediately if it isn't there yet. You can see this default behavior directly by setting the implicit wait to zero.
What is fluent wait in Selenium, and when is it useful?
Fluent wait is a customizable version of explicit wait that adds polling intervals and custom exception handling, useful when elements load unpredictably.
Why do dynamic web applications need waits?
Because elements may load asynchronously via JavaScript/AJAX; waits prevent flaky timing issues when scripts run faster than the UI.
What is a TimeoutException in Selenium, and how do I handle it?
It's the error WebDriverWait throws when a condition never becomes true within the timeout. Catch it in a try/except (Python) or try/catch (Java) block to log the failure, capture a screenshot, or retry, rather than letting the whole test crash.
Why isn’t mixing implicit and explicit waits recommended?
Mixing them can create timing issues and make tests harder to debug; it’s better to use one wait strategy per test session.