Implicit vs Explicit Waits
Synchronization is the number one source of Selenium flakes. Learn the difference between implicit and explicit waits, when to use WebDriverWait with expected conditions, and how FluentWait gives you fine control over polling and ignored exceptions.
What is this?
An implicit wait tells the driver to poll the DOM for a period whenever findElement finds nothing; an explicit wait pauses execution until a specific expected condition — element visible, clickable, text present — is met using WebDriverWait and expected conditions. Implicit and explicit waits should not be mixed in the same suite. FluentWait adds control over poll frequency and ignored exceptions for slow, dynamic pages. Explicit waits are the production default because they target exactly what the test depends on and stop the moment it is true.
Why do you need it?
- Modern pages load asynchronously — DOM ready does not mean the element you need exists or is interactable.
- Implicit waits poll globally for any element but cannot wait for conditions like 'clickable' or 'text present'.
- Explicit waits fail fast with a clear TimeoutException and stop waiting as soon as the condition is true, keeping suites quick.
- A condition is deterministic, unlike an arbitrary sleep that wastes seconds and still races on loaded CI machines.
- Waits handle stale elements: a re-render invalidates old references, and waiting re-locates them at the right moment.
Mental model
Waiting for the coffee machine to finish
An explicit wait
You do not stand there for exactly five minutes — you check the cup until it is full and stop the moment it is. WebDriverWait polls a condition and returns as soon as it is satisfied, then the test continues without burning extra time.
How it works
- driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10)) sets a global poll timeout applied to every findElement call.
- WebDriverWait(driver, Duration.ofSeconds(10)) creates a condition-based poller for a single action.
- Each expected condition returns a callable that the wait invokes every poll (default 500ms) until it returns a truthy value or the timeout expires.
- On success the condition's result is returned (often the located element); on timeout a TimeoutException is thrown naming the condition.
- FluentWait lets you override the poll frequency, timeout and ignored exceptions — e.g. ignore StaleElementReferenceException and keep retrying.
How an explicit wait decides when to proceed.
Key commands
chromedriver --log-level=ALL --log-path=wait-debug.logCapture full driver logs to see the poll cycle when a wait fails.
mvn test -Dtest=WaitsTestRun a single test class exercising explicit waits.
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
python -m pytest tests/test_waits.py -vRun the Python waits suite with per-test output.
pip install seleniumEnsure the Selenium client library is present.
ps aux | grep chromedriverCheck for leaked driver processes after failed runs.
Examples
Waiting for a cart to update in Java
import java.time.Duration;import org.openqa.selenium.By;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.WebDriverWait; WebDriver driver = new ChromeDriver();driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(0));driver.get("https://example.com/cart"); WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(15)); WebElement addToCart = wait.until(ExpectedConditions.elementToBeClickable(By.id("add-to-cart")));addToCart.click(); wait.until(ExpectedConditions.textToBePresentInElementLocated( By.className("cart-count"), "3")); if (driver.findElements(By.className("spinner")).isEmpty()) { System.out.println("Spinner gone, cart updated");} driver.quit();The implicit wait is set to zero so it never fights the explicit wait. elementToBeClickable returns the button only once it is visible and enabled, then the click proceeds. textToBePresentInElementLocated waits for the cart count to actually show 3, and the spinner check confirms the update finished before the test ends.
In production
- Wait for network-driven content (toasts, updated tables and counts) with text-presence or visibility conditions.
- Wait for clickable buttons so tests never click during a transition state.
- Use FluentWait to ignore transient stale-element errors while single-page apps re-render.
- Keep explicit-wait timeouts short (5-15s) so failures surface quickly instead of hanging the whole suite.
Best practices
- Never mix implicit and explicit waits; pick one model consistently (explicit is recommended).
- Prefer elementToBeClickable over visibilityOfElementLocated before clicking.
- Choose the narrowest condition that proves the page reached the state the test needs.
- Centralize timeout values in one config place so CI and local runs share the same tuning.
- Avoid Thread.sleep entirely — a wait on a real condition is always better.
Common mistakes
- Setting a 30-second implicit wait and wondering why every failure takes 30 seconds.
- Using Thread.sleep(5000) everywhere — slow, and still flaky when the machine is loaded.
- Waiting for visibility of an element that exists but is scrolled off-screen, which never becomes visible.
- Using the wrong condition (located vs visible vs clickable) for the actual interaction.
Common issues
Expected condition failed: waiting for element to be clickableThe element is present but covered by an overlay or disabled during the timeout.
Wait for the blocking overlay to disappear, or wait on the element's enabled state.
TimeoutException: waiting for visibility of element located by ...The element never appeared within the timeout.
Verify the locator and that the previous step completed; add a wait on the prerequisite state.
StaleElementReferenceException during the waitThe DOM re-rendered between polls, invalidating the located reference.
Ignore stale-element exceptions in a FluentWait and keep polling, or re-locate after the render completes.
Debugging tips
- On TimeoutException, take a screenshot and dump page source — is the element missing, hidden or blocked?
- Reduce the wait timeout locally and run headed to watch the transition the test misses.
- Log the URL and a few surrounding elements when a wait times out to see where the flow diverged.
- Check the network tab: a timeout often means the API call the UI depends on failed, not Selenium.
Interview checkpoint
Hands-on lab
- Reproduce a race condition with a slow-loading fixture
- Replace fixed sleeps with explicit waits
- Use multiple expected conditions in one flow
- Prove stability by running the test repeatedly
Build a Reliable Wait Strategy
30 min · intermediate
Quick quiz
Which wait keeps retrying a specific condition until it becomes true?
You should always combine an implicit wait with explicit waits for maximum reliability.
A wait for elementToBeClickable keeps timing out even though the element is visible. What is the best next step?
Cheat sheet
implicitlyWait(Duration.ofSeconds(10))Global findElement timeoutWebDriverWait(driver, Duration.ofSeconds(15))Explicit condition waitFluentWaitCustom poll interval + ignored exceptionsThread.sleep(...)Never — guess instead of waitelementToBeClickable(loc)Visible and enabled, ready to clickvisibilityOfElementLocated(loc)Element is visiblepresenceOfElementLocated(loc)Element exists in the DOMtextToBePresentInElementLocated(loc, 'x')Text has appearedinvisibilityOfElementLocated(loc)Loader/overlay is gonestalenessOf(el)Old element has detachedelementToBeSelected(loc)Checkbox/radio is selectedtitleContains('x')Page title updated