Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use an explicit wait for the exact state your next action needs, and keep implicit waits at zero while diagnosing. A navigation reaching its configured readyState does not prove that JavaScript has finished inserting, revealing, or replacing the element you need. If the element can be replaced, locate it again inside the wait instead of reusing an old reference. Also check the browser stack itself: PhantomJS development is suspended, and Selenium removed its PhantomJS capabilities, so increasing a timeout is not a durable fix for an unsupported combination.

Why a PhantomJS wait can fail after the page “loads”

Selenium waits poll a condition until it succeeds or the timeout expires. The useful question is not “Has navigation finished?” but “What must be true before the next command is safe?”

Page-load completion is not application readiness

The page-load state covers assets represented in the HTML. Client-side JavaScript can still fetch data, render a component, remove a loading placeholder, or reveal a button afterward. A wait that only follows navigation therefore can finish before the application is usable.

The condition does not match the action

Presence means that a node exists in the DOM. It does not mean that the node is displayed, enabled, unobstructed, or ready for the operation you intend. Choose visibility when the user must see the element and clickability when the next operation is a click on a visible, enabled element. A correct condition cannot repair a wrong locator.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Implicit and explicit waits interact unpredictably

An implicit wait changes every element-location call. An explicit wait polls its own condition, and that condition may perform element lookups. Combining a nonzero implicit wait with an explicit wait can make each poll take longer than expected and make the total duration difficult to predict. Selenium’s waiting-strategies guidance explicitly says not to mix implicit and explicit waits.

The reference is stale, not slow

Dynamic frameworks often replace a node rather than changing it in place. A stored WebElement then points to a DOM object that no longer exists. This is different from an element that has not appeared yet. Re-find by locator inside the explicit wait when updates can replace nodes; Selenium also provides staleness and invisibility conditions for replacement and disappearance flows.

The PhantomJS stack may be the failure

PhantomJS was a scriptable headless browser and historically used GhostDriver for WebDriver support. Its project homepage now states that development is suspended. Selenium’s Python changelog records PhantomJS deprecation in Selenium 3.8.1 and later removal of PhantomJS capabilities during Selenium 4 development. A timeout adjustment cannot restore support removed from the client stack.

A practical diagnosis before changing the timeout

  1. Capture the exact failure. Record the exception class, complete message, locator, URL, browser and driver versions, Selenium binding and version, PhantomJS/GhostDriver version, and the wait configuration. A TimeoutException means the condition did not become true before the deadline; it does not identify why.
  2. Describe the required state. Decide whether the element must merely exist, be displayed, contain particular text, become enabled, disappear, or be replaced. This determines the condition.
  3. Check the locator independently. Inspect the DOM at the point of failure. A no-such-element result can mean the application has not inserted the node yet, but it can also mean the selector is wrong or the code is on a different frame or page.
  4. Look for replacement. If a component rerenders, do not keep polling a cached WebElement. Poll with the locator so each attempt can obtain the current node.
  5. Remove implicit waiting while investigating. Set the implicit wait to zero and use explicit waits around dynamic operations. This gives each condition a known timeout and polling behavior.
  6. Verify the browser-driver pairing. Check the pinned versions and startup logs. If the combination relies on removed PhantomJS support, plan a move to a maintained browser and its WebDriver rather than adding retries indefinitely.

Use a condition-based explicit wait in Python

The following pattern waits for a visible, enabled button before clicking it:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

# Keep implicit waiting disabled while using explicit waits.
driver.implicitly_wait(0)
wait = WebDriverWait(driver, 10)

button = wait.until(
    EC.element_to_be_clickable((By.ID, "submit"))
)
button.click()

WebDriverWait accepts a timeout and can be configured with a polling interval and ignored exceptions. In the current Python API, the default poll interval is 0.5 seconds and NoSuchElementException is ignored by default. Those defaults belong to the Python binding; do not assume another language binding uses identical syntax or defaults.

Pick the narrowest condition that proves safety

  • presence_of_element_located: the locator resolves to a node in the DOM. Use it when existence alone is sufficient.
  • visibility_of_element_located: the node exists and is displayed. It is appropriate when the next step reads or observes visible content.
  • element_to_be_clickable: the element is visible and enabled. It is a better fit for a click than presence alone.
  • invisibility_of_element_located: a spinner, overlay, or old component is hidden or gone.
  • staleness_of: a previously obtained element has been detached, useful when a refresh replaces a known node.

Re-find nodes that can be replaced

Use a locator in the condition instead of repeatedly inspecting a cached reference:

from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

wait = WebDriverWait(driver, 15)
current_result = wait.until(
    EC.visibility_of_element_located((By.CSS_SELECTOR, "[data-testid='result']"))
)
print(current_result.text)

If the application replaces that result during a refresh, the condition performs a new lookup and returns the current node. If you already hold an old reference and need to wait for its replacement, first wait for staleness, then locate the new node.

Remove fixed sleeps and mixed wait settings

A fixed pause such as time.sleep(5) waits the same amount whether the page is ready immediately or still loading. It also hides whether the real problem is a selector, a replaced node, or an unsupported driver. Replace it with a condition tied to the next operation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #3
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • Brand: Wiley
  • Set of 2 Volumes
  • A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
# Diagnostic baseline: no global implicit delay
driver.implicitly_wait(0)

wait = WebDriverWait(driver, timeout=20, poll_frequency=0.5)
wait.until(EC.visibility_of_element_located((By.ID, "account-panel")))

Use a longer timeout only when the application’s legitimate worst-case latency justifies it. Keep the polling interval and ignored-exception choices deliberate, and log the condition, locator, elapsed time, and final exception so a timeout can be distinguished from a locator error.

PhantomJS-specific compatibility decisions

When a frozen legacy test must keep running

Pin the exact Selenium binding, PhantomJS binary, GhostDriver behavior, and test dependencies that are known to work together. Treat this as a containment measure, not evidence of current support. Test pages that use modern JavaScript, security policies, or browser APIs can behave differently in an obsolete engine.

When to migrate

For new or maintained automation, use a currently supported browser and matching WebDriver. Selenium’s historical guidance pointed users toward headless Chrome or Firefox when PhantomJS was deprecated. Selenium 4 also removed legacy protocol support and uses W3C WebDriver by default. Check the current browser, driver, and binding requirements for the versions you select.

After migration, keep the same synchronization design: explicit, condition-based waits and no accidental combination with a global implicit wait. A browser change may expose selectors or timing assumptions that PhantomJS previously masked; fix those assumptions rather than adding blanket delays.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Troubleshooting branches

TimeoutException while waiting for presence

  • Verify the selector against the DOM produced by the failing browser.
  • Confirm the test is on the expected URL, window, frame, or tab.
  • Check whether JavaScript inserts the node only after another action or request.
  • Wait for the prerequisite state first, then wait for the target node.

Element is present but the click still fails

  • Change presence to visibility or clickability.
  • Wait for an overlay or loading indicator to become invisible.
  • Check that the element is enabled and that the locator did not select a hidden duplicate.
  • Do not treat a larger timeout as a substitute for a wrong condition.

StaleElementReferenceException

  • Assume the framework may have replaced the node.
  • Store the locator, not the WebElement, and resolve it inside the wait or immediately before the action.
  • Use a staleness wait for the old node when the workflow explicitly expects replacement.

NoSuchElementException during a wait

WebDriverWait’s Python implementation normally ignores this exception while polling, but an immediate lookup outside the wait will still raise it. Put the lookup in the expected condition and confirm that the locator is correct. If the exception names a different element than expected, inspect the test flow for an early navigation or frame switch.

Every wait times out after upgrading Selenium

Separate synchronization failures from compatibility failures. Read the startup and session-creation errors, verify the browser-driver pair, and check whether the code still requests PhantomJS capabilities that the installed Selenium version no longer supports. Migrate the session configuration before tuning application waits.

Design waits for reliable and efficient tests

  • Wait at state boundaries. Synchronize after navigation, submission, filtering, and component refreshes where the DOM changes, not after every line.
  • Use one meaningful condition. A condition tied to the next action fails quickly and explains intent better than a chain of arbitrary sleeps.
  • Keep timeouts proportional. A very short timeout creates false failures under normal latency; an excessive timeout makes genuine failures expensive to diagnose. Choose a value from the slowest legitimate environment and record it as configuration.
  • Make replacement explicit. Modern pages may render the same selector repeatedly. Re-locate after each update instead of assuming object identity.
  • Preserve evidence. On failure, capture the exception, URL, locator, page source or relevant DOM state, browser version, and timing information. This distinguishes an application race from a driver defect.

Which wait strategy fits the job?

Choice Use it when Main trade-off
Explicit wait for presence The next step only needs the node in the DOM Does not establish display or interactability.
Explicit wait for visibility or clickability The next step reads a visible element or clicks an enabled one Still depends on a correct locator and compatible browser-driver stack.
Implicit wait A deliberate global element-location delay is required Global behavior can make explicit-wait timing unpredictable; avoid mixing them.
Continue with PhantomJS A frozen, pinned environment is unavoidable Development is suspended and Selenium support was removed; modern-page compatibility is a risk.
Migrate browser and driver Tests need maintained Selenium support Setup and browser-specific assumptions may need updating.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your goal is a static image or PDF rather than interactive browser assertions, ScreenshotNeo returns a capture from one request. Before capture it accepts the cookie or consent banner like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and the response identifies the result with X-Page-Verdict and X-Billed headers.

Use the ScreenshotNeo API documentation for all options, including full-page lazy-image loading, CSS-selector element capture, device and viewport settings, dark mode, retina scale, PDF page ranges, custom CSS or JavaScript, clicks, waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, TTL caching, signed links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage data, and the OpenAPI specification.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python

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)

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo also provides an MCP server for AI agents, with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

Plans and cost

Plan Included shots per month Price
Free 1,000 $0, no card
Starter 3,000 $5
Growth 15,000 $15
Pro 60,000 $39
Scale 250,000 $99
Business 1,000,000 $249

Every feature is available on every plan, and yearly billing provides two months free. Create a free ScreenshotNeo account to get 1,000 screenshots a month without a card.

FAQ

Does a longer explicit timeout fix a stale element?

No. A stale reference identifies an old DOM node; wait for staleness or locate the replacement node again. Extending the timeout only changes how long Selenium looks.

Can PhantomJS still be used for a historical build?

Possibly, if the project is frozen on a known-compatible, pinned stack. That is a legacy containment decision, not a current support guarantee; PhantomJS development is suspended and Selenium removed its PhantomJS capabilities.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Does a longer explicit timeout fix a stale element?

No. A stale reference identifies an old DOM node; wait for staleness or locate the replacement node again. Extending the timeout only changes how long Selenium looks.

Can PhantomJS still be used for a historical build?

Possibly, if the project is frozen on a known-compatible, pinned stack. That is a legacy containment decision, not a current support guarantee; PhantomJS development is suspended and Selenium removed its PhantomJS capabilities.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.