ScreenshotNeo

BlogHow-to

How to Use WebDriverWait in Selenium C#

Use WebDriverWait in Selenium C# to wait for the exact browser state your next action needs, with runnable examples, timeout guidance, and fixes for common errors.

By the ScreenshotNeo team4 October 20268 min read

WebDriverWait lets a Selenium C# test poll for a browser condition and continue as soon as that condition is true. Create a wait with an IWebDriver and a TimeSpan timeout, then pass a predicate to Until. Wait for the state the next action needs—such as visibility or an updated page title—instead of sleeping for a fixed duration.

1. Add Selenium and create a driver

The examples use Selenium’s .NET API. Add the Selenium.WebDriver and Selenium.Support packages to your project. The support package contains WebDriverWait, in OpenQA.Selenium.Support.UI. The API derives WebDriverWait from DefaultWait<IWebDriver>. See the WebDriverWait API.

using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;

using var driver = new ChromeDriver();
driver.Navigate().GoToUrl("https://example.com");

var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));

For a standalone console example, include using System; when your project does not provide implicit global usings. A compatible Chrome browser and driver must be available to Selenium. The rest of this guide focuses on waits; it does not depend on a particular test framework.

2. Wait for the state you need

Wait for an element to be visible

var result = wait.Until(d =>
{
    var element = d.FindElement(By.Id("results"));
    return element.Displayed ? element : null;
});

Console.WriteLine(result.Text);

This object-returning condition succeeds when it returns a non-null element. The successful result is returned from Until, so you can use it without locating the element again. If nullable reference types are enabled, adapt the return annotation to your project’s compiler settings; the wait behavior is the same.

Wait for a boolean condition

wait.Until(d => d.FindElement(By.Id("revealed")).Displayed);

A boolean condition succeeds when it returns true. Selenium’s wait guide uses this form in its C# example. That example’s two-second timeout is illustrative, not a general timeout recommendation.

Wait for a page title or application state

wait.Until(d => d.Title.Contains("Dashboard", StringComparison.Ordinal));
wait.Until(d => d.FindElement(By.Id("save-status")).Text == "Saved");

Prefer a predicate that represents the actual readiness condition: a status changed, a loading indicator disappeared, a result count appeared, or a particular control became enabled. Presence alone only says the element can be found; it does not establish visibility, interactability, or that the application finished the relevant work.

3. What Until does

Until repeatedly calls your function with the driver. A boolean result completes the wait when true; an object result completes it when non-null. In either case, Until returns the successful result. A false or null result keeps polling. An exception propagates unless its type is in the wait’s ignored-exception list. If the condition never succeeds before the timeout, the wait throws a timeout exception. See DefaultWait<T> and IWait<T>.

DefaultWait<T> documents 500 milliseconds as its default timeout and 500 milliseconds as its default polling interval. In normal use, set an explicit timeout in the WebDriverWait constructor, as shown above. Polling interval is a separate setting; changing it does not make an unsuitable condition meaningful or guarantee an exact total elapsed time. Predicate execution and browser command duration affect wall-clock time.

4. Configure timeout, polling, and exceptions

var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10))
{
    PollingInterval = TimeSpan.FromMilliseconds(300)
};

wait.IgnoreExceptionTypes(typeof(ElementNotInteractableException));

var button = wait.Until(d =>
{
    var candidate = d.FindElement(By.Id("continue"));
    return candidate.Displayed && candidate.Enabled ? candidate : null;
});
button.Click();
  • Timeout: pass the maximum intended wait as a TimeSpan to the constructor. Choose it based on the operation and environment; do not treat Selenium’s two-second documentation example as a universal value.
  • Polling interval: set PollingInterval when the default cadence is a poor fit. Selenium’s C# guide demonstrates 300 milliseconds, but that is an example, not a blanket recommendation. More frequent polls mean more condition evaluations and browser commands.
  • Ignored exceptions: use IgnoreExceptionTypes only for exceptions expected to be transient while this particular condition is being checked. The configured types are retried during polling; unlisted exceptions propagate. Selenium’s example shows ElementNotInteractableException for its particular interaction. Do not broadly suppress errors that may indicate a broken locator or test.
  • Timeout message: DefaultWait<T> exposes a message property you can set to make timeout failures more informative. Include the condition and relevant locator or operation.

The documented constructor also has an overload accepting a clock and sleep interval for specialized timing behavior. Most tests should use the standard driver-and-timeout constructor and adjust the polling property only when the test has a concrete need.

5. Use waits without fixed sleeps

A fixed Thread.Sleep always consumes its full delay, even when the page becomes ready immediately, and can still be too short when it does not. An explicit wait checks a predicate repeatedly and proceeds once the condition is met or the timeout is reached. Selenium’s wait documentation describes this explicit-wait pattern.

Write the condition before choosing its timeout: what must be true before the next test command is safe? For example, wait for a success message after saving, or for a button to be both displayed and enabled before clicking it. Avoid a condition that only checks an unrelated page element, since it can pass while the action’s real prerequisite is still missing.

6. Implicit waits and explicit waits

Keep implicit waits modest or disabled when using explicit waits. Selenium’s .NET timeout API warns that increasing the implicit wait can adversely affect runtime, especially with slower element-location strategies. Avoid assuming that implicit and explicit timeout values combine into a simple, predictable total. See ITimeouts.

driver.Manage().Timeouts().ImplicitWait = TimeSpan.Zero;
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));

Use the explicit wait’s condition to describe the specific state needed at each point in the test. This makes the wait’s purpose and eventual timeout failure easier to understand.

7. Expected Conditions in Selenium C#

Do not copy Java or Python Expected Conditions examples into a Selenium 4 .NET test as though the same support library applies. Selenium states: “.NET stopped supporting Expected Conditions in Selenium 4 to minimize maintenance hassle and redundancy.” Express the condition directly as a C# lambda passed to Until. See Selenium’s Expected Conditions documentation.

8. Troubleshooting

Symptom Likely cause Fix
WebDriverWait cannot be found The support namespace or package is missing. Reference Selenium.Support and add using OpenQA.Selenium.Support.UI;.
The wait times out, but the page eventually looks ready The timeout is shorter than the real operation, the locator does not match the final DOM, or the predicate checks the wrong state. Inspect the locator and condition, and choose a timeout appropriate to the operation. Check whether the page replaces the element during rendering.
The wait passes but clicking still fails The predicate only checked presence or visibility, while the control was disabled, covered, or otherwise not ready for the action. Check the condition the click needs, such as displayed and enabled. Application-specific overlays may require waiting for the overlay to disappear.
NoSuchElementException fails the wait immediately The exception was not configured to be ignored, or the test should avoid throwing for an expected absence. Use a condition and exception policy suitable for the expected transient state. Ignore only narrowly justified exception types; otherwise let the error reveal a real locator problem.
An ignored exception keeps hiding a failure The ignore list includes an exception that is not transient for this condition. Remove it or narrow the list. Unlisted exceptions should remain visible so test defects are not retried silently.
Tests become unexpectedly slow after adding waits A large implicit wait may be interacting with repeated element lookups, or each poll performs expensive browser commands. Reduce or disable implicit wait, review the predicate’s work, and use a polling interval appropriate to the condition.
A lambda has a nullable type warning Nullable reference types are enabled and the success/failure return values have different nullability. Annotate or shape the predicate return type for the project’s target framework and nullability settings; object waits use non-null for success.

9. Performance, reliability, and cost

Waits improve reliability when they encode real readiness, but they do not make a flaky condition correct. Keep predicates small and repeatable: each poll may issue WebDriver commands. A shorter polling interval can detect a condition sooner but also increases evaluations; a longer interval can reduce polling work while delaying detection. There is no universally optimal interval in the cited API documentation.

Set timeouts deliberately and make timeout messages identify the operation. Avoid stacking long implicit waits inside explicit-wait predicates. Do not claim a precise runtime from the timeout alone: poll timing and the duration of each predicate evaluation affect how long the wait takes. Selenium itself does not charge per wait; browser, CI, and infrastructure costs depend on the environment running the test.

10. Or skip the browser setup

If your goal is a page image rather than interacting with a live browser in a test, ScreenshotNeo provides a website screenshot API and MCP server. One GET request captures a URL as PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API docs.

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);

The C# wait above is the do-it-yourself method for synchronizing browser tests. ScreenshotNeo is for capturing page output: it accepts cookie or consent banners like a visitor and removes 60+ known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, and failed loads are never billed, and cache hits cost nothing; 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 a month with no card; paid plans start at $5 for 3,000. Sign up free for 1,000 screenshots a month, no card required.

11. FAQ

Does Until return the element?

Yes, when the condition returns an element and the wait succeeds, Until returns that element. Boolean conditions return a boolean result instead.

Can WebDriverWait wait for text?

Yes. Return a boolean comparison for the expected text, or return an object only when the desired text is present.

Should every test use the same timeout?

Not necessarily. Choose a timeout that reflects the operation and environment, and keep the predicate tied to the exact state the next action requires.