Run Web Automation Tests at Scale with Agentic AI
Generate tests with AI agents or automate test suites with Selenium, Playwright and other frameworks. Run tests in parallel on TestMu AI scalable cloud grid.
- TestMu AI (Formerly LambdaTest)
- /
- Blog
- /
- Selenium Wait: Implicit, Explicit & Fluent Wait Commands
Selenium Wait: Implicit, Explicit & Fluent Wait Commands
Selenium waits explained with Java examples: implicit, explicit and fluent waits, the Duration syntax Selenium 4 requires, and why you must not mix them.
Last Updated on:
Selenium has two waits. An implicit wait sets one timeout for every element lookup. An explicit wait (WebDriverWait) waits for a specific condition on one element; fluent wait is an explicit wait with custom polling and ignored exceptions. Use explicit waits. Selenium's docs warn: don't mix implicit and explicit waits, because wait times become unpredictable.
The examples use Selenium 4.52.0 in Java, Python, C# and JavaScript.
Getting a Selenium suite to pass reliably comes down to how it handles waiting. Wait commands keep the script in step with the browser, so each step runs against an element that has finished loading instead of a half-rendered DOM.
This guide covers implicit, explicit and fluent waits, then shows how to wait for a specific element and which condition to choose for it. If you are preparing for an interview, the Selenium interview questions guide covers waits alongside other WebDriver topics.
Overview
Selenium waits synchronize test scripts with web elements loading at different speeds, using implicit waits for global, consistent load times and explicit waits for precise, condition-based synchronization of dynamic elements. These mechanisms prevent race conditions and improve test stability across varying page load times.
Why Do We Need Selenium Waits?
- Preventing race conditions: Selenium waits ensure web elements are fully loaded before interaction, preventing errors where the script executes before the browser reaches the correct state.
- Improving test stability: Selenium waits handle dynamic web pages and prevent test failures caused by timing issues or incomplete element loading. When a wait runs out instead, timeout of 30000ms exceeded explains what the error means in Selenium and other tools.
- Adapting to load times: Selenium waits dynamically adjust scripts to varying page loading speeds, making automated test execution more reliable.
Can We Use Thread.sleep()?
- Thread.sleep() limitations: This Java construct introduces static, fixed delays that make test scripts inefficient by waiting for the specified duration regardless of when the element actually loads.
- Maintenance challenges: Using Thread.sleep() requires adding static delays at multiple points in the code, making test scripts difficult to maintain over time.
What Are the Types of Selenium Waits?
- Implicit Wait: Implicit waits set one global timeout for every element lookup in a driver session, and a lookup that never finds its element throws NoSuchElementException. Default: 0 seconds.
- Explicit Wait: Explicit waits use the WebDriverWait class to wait for one condition, such as visibility or clickability, on one element. Default polling: every 500 milliseconds, with a TimeoutException if the condition never holds.
- Fluent Wait: Fluent waits use the FluentWait class, an explicit wait with a custom polling interval and a list of exceptions to ignore while waiting.
- SmartWait: SmartWait is a TestMu AI cloud grid capability, not a Selenium wait type, that checks each element is visible, enabled and stable before every Selenium action.
What are the Common Mistakes to Avoid with Selenium Waits?
- Over-relying on Implicit Waits: Relying solely on implicit waits can cause synchronization issues, whereas explicit or fluent waits provide more precise control.
- Setting improper durations: Configuring wait times that are too short or too long leads to inconsistent and unreliable test results during execution.
- Mixing wait strategies: Combining implicit and explicit wait types in the same script can cause conflicts and should be avoided to maintain consistency.
Why Do We Need Selenium Waits?
The primary challenge in test automation is ensuring the application is appropriately configured to execute a specific Selenium command as intended. One of the most common issues with test automation is race conditions. In a race condition, either the browser reaches the right state first (which results in the desired functionality), or the Selenium code gets executed first (which leads to unintended results). This race condition is one of the main reasons test results are unreliable.
The reason for such race conditions depends on many aspects, like network speed, content size, and the frontend technology/framework used. For Instance, Javascript frameworks like React or Angular take some time to load the different objects on the web page due to the dynamic update to the Document Object Model (also known as DOM).
Without an appropriate wait mechanism, automation tests produce inconsistent results: the same test passes on a fast run and fails on a slow one. Unstable test execution sends developers chasing failures that are not real bugs. Selenium waits fix this by making each command wait for the page state it depends on.
Why Not Use Thread.sleep() in Selenium?
Short answer: don't. Thread.sleep() is a Java construct that stops the program's execution for a specified period (the same idea as time.sleep() in Python, Thread.Sleep() in C# and a setTimeout() pause in JavaScript). It can give automation test scripts the pause they need, but it brings problems that discourage its use:
- Make Test Scripts Inefficient: Invocation of Thread.sleep() method waits for the specified period irrespective of any situation. This static behavior leads to unnecessary delays in executing the test scripts. Regardless of the load time of the elements while testing, the script will wait for a static duration and increase the test execution time.
- Requires Explicit addition after every Selenium Command: While adding waits in the test scripts using Thread.sleep(), it requires adding it all the places, even though there is a requirement of a constant wait before accessing any element of the web page. This makes the test scripts difficult to maintain with time.
- Sleep Duration Calculation: Determining the correct values for the sleep duration would become an essential and challenging task for every Selenium command.
Selenium waits solve these problems by waiting for a condition instead of a fixed time, so a step continues as soon as the page is ready.
What are Selenium Waits?
Selenium Waits is a test automation concept defined as three commands: Implicit Waits, Explicit Waits, and Fluent Waits, that facilitate synchronization between script actions and dynamic web elements.
Each wait polls for a condition and continues as soon as it holds, so the test moves at the speed of the page rather than at a fixed delay. A slow response then costs a few extra polls instead of a failed step.
Types of Selenium Wait Commands
Selenium provides three primary types of wait commands to handle different timing scenarios and enhance the reliability of the automated tests as follows:
- Implicit Wait: Implicit Wait in Selenium is a global wait that applies to all elements in the script. It sets a maximum wait time for any element to become available before interaction. If the element appears within the specified time, the script continues; otherwise, the lookup throws a NoSuchElementException.
- Explicit Wait: Explicit Wait in Selenium is a more granular approach that allows you to wait for a specific condition or element. Explicit waits are applied to individual elements and provide better control and precision. It often uses the WebDriverWait class and expected conditions to define custom waiting criteria. Explicit waits are useful for efficiently handling dynamic web elements with different load times.
- Fluent Wait: Fluent Wait in Selenium allows one to wait for a specific condition to be met with a custom frequency of checking the condition. Fluent waits are particularly useful when dealing with elements that may take varying times to load or change state. This wait is created using the FluentWait class and configured with options like timeout, polling frequency, and exceptions to ignore.
Watch the video to learn about different Selenium wait methods.
Implicit Wait In Selenium
In Selenium, an implicit wait is a mechanism instructing the WebDriver to wait for a certain period before throwing an exception. It is applied globally to the entire script, and its primary purpose is to wait for elements to be present in the DOM (Document Object Model) before performing actions on them.
When an implicit wait is set, the WebDriver will repeatedly poll the DOM for a specified duration until the element is found or the timeout period expires. If the element is found within the specified time, the WebDriver proceeds with the next step in the script. An exception is thrown if the element is not found during the implicit wait period.
For a complete breakdown of all wait strategies and how to choose between them, this guide to Selenium wait for page to load covers implicit, explicit, and fluent waits alongside page load strategies and AJAX-specific patterns.
By default, the value for implicit wait is set to zero, which means that if the element is not found, it will immediately return an error. To enable the Implicit Wait In Java, the following syntax is used on the web driver object.
import java.time.Duration;
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
Set the implicit wait once, immediately after initializing the WebDriver. It then applies to every element lookup for the rest of that driver session.
Older tutorials pass a time unit instead, as in implicitlyWait(10, TimeUnit.SECONDS). Selenium 4 removed that overload along with the other TimeUnit-based timeout methods, so the Duration form above is the only one that compiles against current releases. Add java.time.Duration to your imports.
One rule travels with the implicit wait. Per the Selenium documentation on waiting strategies: “Do not mix implicit and explicit waits. Doing so can cause unpredictable wait times. For example, setting an implicit wait of 10 seconds and an explicit wait of 15 seconds could cause a timeout to occur after 20 seconds.”
So treat it as a choice rather than a layer. If any part of your suite uses WebDriverWait or FluentWait, leave the implicit wait at its default of zero.
What Is Explicit Wait in Selenium?
Explicit wait in Selenium pauses one step of a test until a condition you name is true, such as an element becoming visible or clickable, and throws a TimeoutException if that does not happen within the timeout. In Java, a Selenium explicit wait is a Selenium WebDriverWait object you create where you need it, not a setting applied to the whole driver.
The Selenium documentation describes explicit waits as loops that poll the application for a specific condition and move on to the next command as soon as it evaluates to true. Unlike an implicit wait, which applies to every element lookup, each explicit wait covers one condition on one element.
Puppeteer's closest equivalent is page.waitForSelector(), and Puppeteer timeout covers how its limit is set and what it throws. Cypress has no wait object to create: Cypress timeout covers how its queries retry and how to give one step more time.
For a quick visual walkthrough of this concept, watch the video below from TestMu AI.
Subscribe to the TestMu AI YouTube channel for more tutorials on testing and automation.
The basic form takes the driver and a timeout, then passes a condition to until(), which returns the element once the condition holds:
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("exampleId")));
This snippet assumes no implicit wait is in play. If one is set, its global timeout stacks on top of this condition and the wait you actually get is neither 10 seconds nor the implicit value.
How Selenium Explicit Wait Works
The until() method evaluates the condition again and again. Per the FluentWait API reference, which WebDriverWait extends, it stops when one of these happens:
- The condition returns a value - anything other than null or false ends the wait, and until() returns that value. That is why the visibility condition above hands back a WebElement.
- The timeout expires - until() throws a TimeoutException.
- The condition throws an exception the wait does not ignore - the exception propagates at once. WebDriverWait ignores NotFoundException by default, the parent class of NoSuchElementException, so an element that does not exist yet is retried instead of failing the step.
- The thread is interrupted - rare in a test, but it also ends the wait.
Between checks, WebDriverWait sleeps for its polling interval, 500 milliseconds by default. Both behaviors show up in the failure message. This wait ran on the TestMu AI cloud grid against an element id that does not exist on the page:
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(3));
try {
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("profile")));
} catch (TimeoutException e) {
e.getMessage().lines().limit(2).forEach(System.out::println);
}
Output:
Expected condition failed: waiting for visibility of element found by By.id: profile, but... org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":"#profile"}.
(tried for 3 seconds with 500 milliseconds interval)
The NoSuchElementException in that message is the last error the wait ignored while polling, not the reason the step failed. The step failed because the condition never held within 3 seconds, so check the locator and the condition before you raise the timeout.
Explicit Wait Syntax in Selenium 4
The older new WebDriverWait(driver, 10) constructor, which took a plain number of seconds, was removed in Selenium 4. The WebDriverWait API reference lists the current constructors, and each one takes a Duration:
- WebDriverWait(driver, timeout) - the usual form, polling every 500 milliseconds.
- WebDriverWait(driver, timeout, sleep) - the second Duration sets the polling interval.
- WebDriverWait(driver, timeout, sleep, clock, sleeper) - also takes the Clock and Sleeper the wait uses to measure time and pause. Test code rarely needs it.
Because WebDriverWait extends FluentWait, it also inherits withMessage(), ignoring(), pollingEvery() and withTimeout(). The condition can be any lambda that returns a value or null, which covers checks that ExpectedConditions does not have. This wait polls every 250 milliseconds, carries its own failure message, and returns the loaded text from a TestMu AI Selenium Playground page:
WebDriverWait custom = new WebDriverWait(driver, Duration.ofSeconds(10), Duration.ofMillis(250));
custom.withMessage("random user never loaded")
.ignoring(StaleElementReferenceException.class);
driver.findElement(By.id("save")).click();
String text = custom.until(d -> {
String t = d.findElement(By.id("loading")).getText();
return t.contains("First Name") ? t : null;
});
System.out.println(text.replace("\n", " ").trim());
Output (the name changes on every run):
First Name : Vickie Last Name : Murray
The withMessage() text goes into the TimeoutException, so a CI log names the step that timed out. The ignoring() call covers a page that re-renders the element between the lookup and getText(), which would otherwise end the wait with a StaleElementReferenceException.
How to Wait for an Element in Selenium?
To wait for an element in Selenium, create a WebDriverWait and pass until() the condition the next step depends on: visibility before reading text, clickability before a click, invisibility before acting on whatever a spinner covered. There is no single "element loaded" state, so the condition you choose decides what the wait proves.
Waiting for an element to load works the same way. Wait for the content the next step reads, such as the text or the image, not for the container that holds it. The Selenium Playground example below shows what goes wrong otherwise.
Wait Conditions by Goal
Java's ExpectedConditions class and Python's expected_conditions module ship ready-made conditions for the common goals. Pick the row that matches what the next line of the test does:
| Goal | Java (ExpectedConditions) | Python (expected_conditions) | What the wait proves |
|---|---|---|---|
| Element exists | presenceOfElementLocated | presence_of_element_located | The element is in the DOM. It may still be hidden or empty. |
| Element is visible | visibilityOfElementLocated | visibility_of_element_located | The element is in the DOM and displayed. |
| Element is clickable | elementToBeClickable | element_to_be_clickable | The element is visible and enabled. Another element can still cover it. |
| Element shows text | textToBePresentInElementLocated | text_to_be_present_in_element | The element's text contains the given string. |
| Element is gone | invisibilityOfElementLocated | invisibility_of_element_located | The element is hidden or no longer in the DOM, as with a loading spinner. |
| Attribute has a value | attributeToBe | text_to_be_present_in_element_attribute | The attribute equals the value in Java, or contains it in Python. |
| Element count | numberOfElementsToBe | No built-in; use a lambda | Exactly that many elements match the locator. |
| Old element replaced | stalenessOf | staleness_of | The element you hold a reference to is no longer attached to the DOM. |
| Frame is ready | frameToBeAvailableAndSwitchToIt | frame_to_be_available_and_switch_to_it | The frame is available, and the driver has switched into it. |
| Alert is open | alertIsPresent | alert_is_present | An alert is open, and the wait returns it. |
For an element count in Python, pass a lambda such as lambda d: len(d.find_elements(By.CSS_SELECTOR, "li")) == 3. For worked examples of each condition in both languages, read ExpectedConditions in Selenium.
Wait for an Element on the Selenium Playground
The Dynamic Data Loading demo in TestMu AI's Selenium Playground shows why the condition matters. Clicking Get Random User writes "loading..." into the div with the id loading straight away, then replaces it with a photo and a name once the data arrives.
This Java test waits on that div twice, first for presence and then for the photo, and prints how long each wait took after the click. It runs on the TestMu AI cloud grid with your LT_USERNAME and LT_ACCESS_KEY:
import java.net.URL;
import java.time.Duration;
import java.util.HashMap;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
public class WaitForElementDemo {
public static void main(String[] args) throws Exception {
ChromeOptions options = new ChromeOptions();
options.setBrowserVersion("latest");
HashMap<String, Object> ltOptions = new HashMap<>();
ltOptions.put("username", System.getenv("LT_USERNAME"));
ltOptions.put("accessKey", System.getenv("LT_ACCESS_KEY"));
ltOptions.put("platformName", "Windows 11");
ltOptions.put("build", "Selenium Waits");
ltOptions.put("name", "Wait for element");
options.setCapability("LT:Options", ltOptions);
WebDriver driver = new RemoteWebDriver(new URL("https://hub.lambdatest.com/wd/hub"), options);
try {
driver.get("https://www.testmuai.com/selenium-playground/dynamic-data-loading-demo/");
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(15));
driver.findElement(By.id("save")).click();
long start = System.currentTimeMillis();
// Too early: #loading is already in the DOM, showing a placeholder
WebElement box = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("loading")));
System.out.printf("present after %d ms: %s%n",
System.currentTimeMillis() - start, box.getText());
// Right condition: the photo only arrives with the user data
wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#loading img")));
System.out.printf("loaded after %d ms: %s%n",
System.currentTimeMillis() - start, box.getText().replace("\n", " ").trim());
} finally {
driver.quit();
}
}
}
Output on Chrome 156 and Windows 11 (the name changes on every run):
present after 425 ms: loading...
loaded after 2596 ms: First Name : Christian Last Name : Olsen
The presence wait returned in under half a second with the placeholder text, because the div was in the DOM before the data arrived. A test that read the name at that point would pass or fail depending on how fast the data came back. The visibility wait on the photo returned the real name after about 2.6 seconds.
Across three runs on the TestMu AI grid, presence returned in 165 to 425 ms and the data took 2.0 to 2.6 seconds. Set the timeout well above the slowest normal response, as the 15 seconds here does, so a busy CI runner does not turn a slow response into a failure.
Fluent Wait In Selenium
In Selenium, Fluent wait is an explicit wait with custom polling and ignored exceptions. It provides a more flexible way of waiting for certain conditions to be met before proceeding with the execution of the script. It implements the Wait interface and allows you to define the polling frequency and exceptions to ignore during the waiting period.
The fluent wait command is implemented using the Selenium FluentWait class in Java. The key feature of FluentWait is its "fluent" or chainable syntax, where you can apply different conditions and configurations in a chain.
Wait<WebDriver> fluentWait =
new FluentWait<WebDriver>(driver)
.withTimeout(
Duration.ofSeconds(60))
.pollingEvery(Duration.ofSeconds(2))
.ignoring(NoSuchElementException.class);
WebElement webElement =
fluentWait.until(ExpectedConditions.presenceOfElementLocated(By.id("exampleId")));
The builder chain sets the timeout, the polling interval and the exception to ignore while waiting. The finished wait is then used like any explicit wait: pass a condition or a Function to its until() method when accessing an element.
Selenium Wait Examples in Java, Python, C# and JavaScript
The pattern is the same in every binding: create a wait with a timeout, then pass it the condition to wait for. Pick your language below. Each example opens a public demo page with a Start button, clicks it, and waits for the "Hello World!" text that the page adds a few seconds later.
The full Java example, with every import. Selenium 4 takes a Duration for every timeout, and the polling interval defaults to 500 milliseconds.
import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Wait;
import org.openqa.selenium.support.ui.WebDriverWait;
public class SeleniumWaitExample {
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
try {
driver.get("https://the-internet.herokuapp.com/dynamic_loading/2");
// Explicit wait: one condition on one element
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
driver.findElement(By.cssSelector("#start button")).click();
WebElement message = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("finish")));
System.out.println(message.getText());
driver.navigate().refresh();
driver.findElement(By.cssSelector("#start button")).click();
// Fluent wait: an explicit wait with custom polling and ignored exceptions
Wait<WebDriver> fluentWait = new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(10))
.pollingEvery(Duration.ofMillis(250))
.ignoring(NoSuchElementException.class);
WebElement same = fluentWait.until(d -> d.findElement(By.id("finish")));
System.out.println(same.getText());
} finally {
driver.quit();
}
}
}
In Python, WebDriverWait covers both the explicit and the fluent case: poll_frequency and ignored_exceptions turn it into a fluent wait.
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
driver = webdriver.Chrome()
driver.get("https://the-internet.herokuapp.com/dynamic_loading/2")
# Explicit wait: one condition on one element
wait = WebDriverWait(driver, timeout=10)
driver.find_element(By.CSS_SELECTOR, "#start button").click()
message = wait.until(EC.visibility_of_element_located((By.ID, "finish")))
print(message.text)
driver.refresh()
driver.find_element(By.CSS_SELECTOR, "#start button").click()
# Fluent wait: the same class with custom polling and ignored exceptions
fluent = WebDriverWait(driver, timeout=10, poll_frequency=0.25,
ignored_exceptions=[NoSuchElementException])
print(fluent.until(lambda d: d.find_element(By.ID, "finish")).text)
driver.quit()
For more patterns, including waits outside Selenium, read the Python waits guide.
Selenium 4 for .NET has no built-in ExpectedConditions class, so the condition is a lambda that returns the element, or null while the wait should continue. For more, read the explicit fluent wait in Selenium C# and WebDriverWait in Selenium C sharp guides.
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
using IWebDriver driver = new ChromeDriver();
driver.Navigate().GoToUrl("https://the-internet.herokuapp.com/dynamic_loading/2");
// Explicit wait: one condition on one element
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
driver.FindElement(By.CssSelector("#start button")).Click();
IWebElement message = wait.Until(d =>
{
var element = d.FindElement(By.Id("finish"));
return element.Displayed ? element : null;
});
Console.WriteLine(message.Text);
driver.Navigate().Refresh();
driver.FindElement(By.CssSelector("#start button")).Click();
// Fluent wait: the same class with custom polling and ignored exceptions
var fluent = new WebDriverWait(driver, TimeSpan.FromSeconds(10)) { PollingInterval = TimeSpan.FromMilliseconds(250) };
fluent.IgnoreExceptionTypes(typeof(NoSuchElementException));
Console.WriteLine(fluent.Until(d => d.FindElement(By.Id("finish"))).Text);
In JavaScript, driver.wait() takes a condition from until and a timeout in milliseconds, and returns a promise.
const { Builder, By, until } = require('selenium-webdriver');
(async () => {
const driver = await new Builder().forBrowser('chrome').build();
try {
await driver.get('https://the-internet.herokuapp.com/dynamic_loading/2');
// Explicit wait: one condition on one element
await driver.findElement(By.css('#start button')).click();
const message = await driver.wait(until.elementLocated(By.id('finish')), 10000);
await driver.wait(until.elementIsVisible(message), 10000);
console.log(await message.getText());
} finally {
await driver.quit();
}
})();
For async and promise-based patterns, read the JavaScript wait in Selenium WebDriver guide.
None of these examples sets an implicit wait. That is deliberate: the implicit wait stays at its default of zero so it cannot stack on top of the explicit waits.
Implicit vs Explicit vs Fluent Wait in Selenium
The difference between an implicit and an explicit wait is scope. An implicit wait is one global timeout for every element lookup, while an explicit wait waits for one condition on one element. Fluent wait is an explicit wait with custom polling and ignored exceptions, so the practical choice is between implicit and explicit. Choose explicit, and do not mix the two.
| Characteristic | Implicit Wait | Explicit Wait | Fluent Wait |
|---|---|---|---|
| Scope | Affects all elements across the website universally. | Can be applied individually to specific elements. | Allows for personalized waiting strategies tailored to specific elements. |
| Complex Conditions Supported | Best suited for basic checks on whether an element is present or not. | Supports a variety of conditions, like visibility or clickability, through explicit Conditions. | Offers a high level of flexibility by accommodating user-defined specific conditions. |
| Configuration | Set globally once for a consistent application throughout the entire website. | Configurable independently for different elements, providing nuanced control. | Resembles Explicit Wait but introduces additional configurations for heightened precision. |
| Use case | Well-suited for straightforward scenarios with consistent loading times. | Ideal for tackling complex situations, especially when the loading behavior is unpredictable. | Effective in dynamic scenarios marked by changes and variable loading times. |
| Wait Time Configuration | Globally set, ensuring a uniform waiting time across the entire site. | Can be configured individually for specific elements or scenarios, allowing for granular control. | Customizable on a per-element basis, enabling tailored waiting times. |
| Polling Interval Config | Polling happens inside the browser driver, and Selenium has no setting for it. | Permits users to set the frequency of condition checks, defaulting to 500ms intervals. | Adheres to the same polling interval configuration as Explicit Wait. |
| Ignoring Exceptions | Lacks the ability to selectively ignore exceptions. | Allows for selective suppression of specific errors during the waiting period. | Aligns with Explicit Wait in terms of exception handling. |
| Combining With Other Waits | Should not be combined with Explicit or Fluent Waits. The global timeout stacks on top of the condition-based one. | Safe alongside Fluent Wait, as long as the implicit wait stays at its default of zero. | Safe alongside Explicit Wait, on the same condition that no implicit wait is set. |
| Flexibility | Relatively straightforward with limited customization options. | Offers enhanced adaptability, accommodating various waiting scenarios. | Highly adaptable, particularly beneficial for specific and nuanced situations. |
| Readability and Expressiveness | Basic in nature due to its global application, providing less detailed insights. | Exhibits greater expressiveness, especially when employing diverse Conditions. | Demonstrates high expressiveness with a fluent API, contributing to code clarity. |
How Do Selenium Waits Reduce Flaky Tests?
Waits reduce flaky Selenium tests by replacing a guess about timing with a check of the actual page state. A fixed sleep passes when the page is fast and fails when CI is busy, while an explicit wait continues the moment its condition holds and fails only when the condition never does.
The cause is common. In Luo et al.'s empirical analysis of flaky tests in Apache Software Foundation projects, async waits accounted for 45% of the 161 flaky test fixes they classified, more than any other category.
Selenium tests hit this constantly, because every click can trigger a request that the next command races against.
To get the benefit in practice:
- Replace every fixed sleep with a condition: wait for visibility, clickability or text on the element the next step needs.
- Wait on the right condition: an element that is present in the DOM is not always visible or enabled, so elementToBeClickable() fails less often than a presence check before a click.
- Keep the implicit wait at zero: it makes timeouts unpredictable and hides which condition actually failed.
- Do not retry your way out of a timing bug: a test that passes only on a rerun is still flaky. Find the missing wait and fix it.
For fixes beyond waits, read how to fix a flaky Selenium test suite, or the flaky test guide for causes, retries and quarantine.
Note: On TestMu AI's Automation Cloud, the SmartWait capability runs actionability checks before every Selenium action and holds the action until the element is visible, enabled and stable, for up to the 5 to 120 seconds you set in LT:Options. If the checks never pass, the test gets the matching Selenium error, so a timing problem still fails instead of hiding.
Common Mistakes to Avoid While Using Selenium Waits
Exploring Selenium waits is essential, but avoiding common mistakes is equally important. Some pitfalls to avoid while using Selenium waits:
- Excessive Reliance on Implicit Waits: An implicit wait only checks whether an element has reached the DOM, so it cannot tell you the element is visible or clickable yet. In dynamic scenarios, replace it with an Explicit or Fluent Wait rather than running both, and set the implicit wait back to zero when you do.
- Inadequate Wait Times: A timeout close to the normal response time fails whenever a CI runner is busy, while a very long one only delays the failure report. Base the timeout on the slowest response you consider normal, with headroom.
- Waiting on the Wrong Condition: A presence check passes as soon as the element is in the DOM, even when it still holds a placeholder, as the Selenium Playground example above shows. Match the condition to the next step: visibility to read, clickability to click, text for loaded content.
- Ignoring StaleElementReferenceException: Handle StaleElementReferenceException with care, which raises when an element is no longer attached to the DOM but a reference to the element is still being used. Ignoring it can lead to failures when interacting with stale elements. Use Explicit Waits judiciously to address this issue.
- Forgetting to Reset Implicit Waits: After modifying the Implicit Wait globally, remember to reset it. Forgetting to do so can impact other parts of your script, and maintaining consistency is crucial.
- Mixing Implicit With Explicit or Fluent Waits: Explicit and Fluent Waits sit together safely, since both are scoped to one condition at a time. An implicit wait is global, so pairing it with either makes the two timeouts stack and the real wait time becomes hard to predict. Pick one model per suite, and keep the implicit wait at zero whenever that model is Explicit or Fluent.
- Writing Your Own Polling Loops: WebDriverWait already handles the polling, the timeout, and the exception filtering. A hand-rolled loop around Thread.sleep() ends up longer than the class it replaces and behaves worse on slow pages.
Conclusion
Pages do not finish loading on a schedule, which is why Selenium ships wait commands at all. Thread.sleep() pauses for a fixed interval whether the element arrives in 200 milliseconds or never arrives. Selenium waits poll for a condition and continue the moment it holds.
The three types divide by scope. Implicit Wait is global and confirms only that an element reached the DOM. Explicit Wait targets one condition on one element through WebDriverWait. Fluent Wait does the same while letting you set the polling interval and the exceptions to ignore. To wait for an element, pick the condition the next step needs, not just presence in the DOM.
The practical rule is to pick one of them. An implicit wait running alongside WebDriverWait or FluentWait makes the two timeouts stack, and the wait you get back is neither number you configured. Keep the implicit wait at zero, drive your web automation with explicit or fluent waits, and the timing stays predictable as the suite grows.
Testing from the terminal? Kane CLI by TestMu AI lets SDETs and developers plan, write, run and debug tests from the command line.
Author
Navin Chandra is a Member of Technical Staff at TestMu AI, building the open-source automation that powers its Selenium and Appium cloud grid. A committer to both Selenium and Appium, he implemented WebDriver BiDi support in Selenium for real-time browser events and bidirectional control and is developing Apple's iOS RemoteXPC protocol in Appium to enable low-level wireless communication with iOS system services. He contributes to Selenium across multiple language bindings as a member of the Selenium GitHub organization. He has served as a Google Summer of Code mentee and mentor at openSUSE and an LFX mentee at CNCF's KubeArmor, and is a SUSE Certified Deployment Specialist. Navin holds a B.Tech in Computer Science.
Reviewer
Himanshu Sheth is the Director of Marketing (Technical Content) at TestMu AI, with over 8 years of hands-on experience in Selenium, Cypress, and other test automation frameworks. He has authored more than 130 technical blogs for TestMu AI, covering software testing, automation strategy, and CI/CD. At TestMu AI, he leads the technical content efforts across blogs, YouTube, and social media, while closely collaborating with contributors to enhance content quality and product feedback loops. He has done his graduation with a B.E. in Computer Engineering from Mumbai University. Before TestMu AI, Himanshu led engineering teams in embedded software domains at companies like Samsung Research, Motorola, and NXP Semiconductors. He is a core member of DZone and has been a speaker at several unconferences focused on technical writing and software quality.
Selenium Waits FAQs
Did you find this page helpful?
More Related Blogs
TestMu AI forEnterprise
Get access to solutions built on Enterprise
grade security, privacy, & compliance
- Advanced access controls
- Advanced data retention rules
- Advanced Local Testing
- Premium Support options
- Early access to beta features
- Private Slack Channel
- Unlimited Manual Accessibility DevTools Tests







