The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
ElementNotInteractableException means Selenium found a DOM element, but that element could not perform the requested action in its current state. In headless Chrome, diagnose the element before changing browser flags: confirm the locator, use an action the element supports, wait for the application state you need, and check visibility, viewport position, and overlays. Only then verify the headless configuration and Chrome/ChromeDriver versions.
What the exception actually means
Selenium’s documentation defines this exception as an attempt to interact with an element that is “not interactable in its current state.” Presence in the DOM is not enough. A matching node may be hidden with CSS, disabled, outside the usable page state, covered by another element, or not the control you intended to select.
Headless mode can expose layout or timing differences, but it is not established as a universal cause of this exception. Treat a headed-versus-headless difference as a diagnostic clue, not as proof that removing headless mode fixes the application.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsUse this diagnostic order
- Confirm the page and locator. Make sure navigation and preceding actions completed. Check that the selector identifies the intended element and, ideally, only one match. A broad selector can return a hidden template control while a visible duplicate is the real target.
- Match the operation to the element.
send_keysbelongs on a text field or another keyboard-interactable control.clearrequires an editable, resettable control. Do not type into a wrapper, label, icon, or container merely because it contains the visible input. - Check displayed state and viewport. An element can exist but be hidden, have zero usable size, or be outside the current view. Selenium attempts to scroll an out-of-viewport element into view, but scrolling cannot make a
display:none, disabled, or otherwise unavailable control interactable. - Wait for the condition the next action needs. A completed navigation does not prove that JavaScript has created, enabled, or revealed the control. Wait for visibility, clickability, a selector, or an application-specific state.
- Separate obstruction from non-interactability. If another element covers the click point, Selenium reports
ElementClickInterceptedException. Investigate cookie banners, modals, sticky headers, animations, and other overlays rather than treating the problem as a missing element. - Check headless setup last. Use the documented
--headless=newargument where appropriate and verify that Chrome and ChromeDriver have matching major versions. These are configuration checks, not a substitute for element diagnosis.
A reliable headless Chrome baseline
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument("--headless=new")
options.add_argument("--window-size=1365,900")
driver = webdriver.Chrome(options=options)
try:
driver.get("https://example.com")
print(driver.title)
finally:
driver.quit()
A fixed window size makes responsive breakpoints more predictable. If your site presents a mobile layout at the default headless size, a selector or overlay that works on desktop may no longer be present or visible.
#1 Best Overall
Locator and element-type checks
Make the selector specific
Prefer a stable ID, name, accessible role, or a narrowly scoped CSS selector. Then inspect how many elements match before acting:
from selenium.webdriver.common.by import By
matches = driver.find_elements(By.CSS_SELECTOR, "form#login input[name='email']")
print("matches:", len(matches))
for item in matches:
print(item.tag_name, item.is_displayed(), item.is_enabled(), item.get_attribute("type"))
If the count is zero, the page or frame is wrong, or the control has not been created yet. If it is greater than one, refine the locator instead of selecting the first match blindly.
Use the control that owns the value
For a text field, locate the input or textarea, not its label or parent:
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchRank #2
email = driver.find_element(By.NAME, "email")
email.clear()
email.send_keys("[email protected]")
For a native checkbox or button, use click(). For a custom widget, identify the element that the application makes keyboard- or pointer-interactable; a decorative span may not be the correct target.
Wait for the right state, not an arbitrary delay
Use an explicit wait tied to the next operation. Selenium’s waiting guidance says not to mix implicit and explicit waits because their polling behavior can produce unpredictable timing.
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver, 20)
email = wait.until(
EC.visibility_of_element_located((By.NAME, "email"))
)
wait.until(lambda d: email.is_enabled())
email.clear()
email.send_keys("[email protected]")
For a click, wait for clickability:
submit = wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "button[type='submit']"))
)
submit.click()
Visibility means Selenium can see the element; clickability additionally checks that it is enabled. Neither condition guarantees that an unrelated overlay will not intercept the center point, so inspect the page when the exception changes to a click-intercepted error.
Rank #3
Wait for application state
When a framework renders after navigation, wait for a meaningful signal such as a loading indicator disappearing, a button becoming enabled, or a results container appearing. A fixed sleep can be shorter than a slow run and unnecessarily long on a fast run.
Recommended Free Tools
Frames, windows, and stale page context
A correct locator still fails if the element belongs to an iframe. Switch into the frame before locating it:
frame = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "iframe.payment")))
driver.switch_to.frame(frame)
card = wait.until(EC.visibility_of_element_located((By.NAME, "cardnumber")))
card.send_keys("4111111111111111")
driver.switch_to.default_content()
Likewise, after opening a new tab, switch to its window handle. After navigation or a reactive re-render, reacquire an element rather than reusing a reference to a node that has been replaced.
Rank #4
Viewport, overlays, and scrolling
Selenium scrolls an out-of-view target as part of normal interaction, but sticky headers, cookie consent dialogs, chat widgets, and animations can still cover the center. First wait for the overlay to disappear or close it through its real UI. If the page needs a deliberate scroll, use it to bring the target into a stable position:
target = wait.until(EC.visibility_of_element_located((By.ID, "details")))
driver.execute_script(
"arguments[0].scrollIntoView({block: 'center', inline: 'nearest'});",
target,
)
wait.until(lambda d: target.is_displayed() and target.is_enabled())
target.click()
Do not make a JavaScript DOM click your default fix. It bypasses the normal user-like interaction path and can hide a real visibility, overlay, or timing defect. Use it only when the application explicitly requires a non-user DOM operation and you understand the trade-off.
Common symptoms and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
Element is found but send_keys fails |
Wrong node, such as a wrapper or label | Locate the editable input or textarea; inspect tag and type. |
| Element count is greater than one | Selector also matches a hidden template or duplicate | Scope the selector and verify visibility before acting. |
| Works headed, fails headless | Different viewport, responsive layout, timing, or overlay | Set a window size, capture diagnostics, and wait for the required state. |
| Click reports intercepted | Another element covers the center | Close or wait out the overlay, then scroll and retry. |
| Element appears after a delay | JavaScript has not rendered or enabled it | Use an explicit wait for visibility, enabled state, or an application signal. |
| Every interaction fails after switching pages | Wrong frame or window context | Switch to the correct iframe or window, then reacquire the element. |
| Session fails before the test starts | Chrome and ChromeDriver major versions do not match | Install compatible major versions and verify the actual binaries being launched. |
Capture evidence when the failure is intermittent
Record the current URL, title, viewport, locator, element count, displayed/enabled values, and a screenshot at the failure point. That evidence distinguishes a selector mistake from a race condition or overlay. Keep the browser log and, where permitted, the page HTML so you can see whether the expected control existed at the time of failure.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
If your goal is a clean page image rather than Selenium interaction, ScreenshotNeo makes one GET request for a screenshot or PDF. Before capture it accepts cookie/consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for the other 63 options, including full-page lazy-image loading, CSS-selector element capture, device presets, custom CSS and JavaScript, waits, request blocking, cookies and headers, geolocation, PDF controls, resizing, TTL caching, signed links, asynchronous webhooks, bulk capture, usage reporting, and the OpenAPI specification. A free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.
Best Value
Cost and reliability considerations
- Explicit waits improve reliability by synchronizing with the application rather than a guessed delay.
- A fixed viewport reduces responsive-layout surprises, but test the viewport your users actually receive.
- Retry only after collecting state. Blind retries can conceal a deterministic locator or overlay defect.
- Keep Chrome and ChromeDriver major versions aligned; configuration changes should follow element-level checks.
- For image capture workloads, ScreenshotNeo bills only clean shots and exposes verdict and billing headers, so failed loads and cache hits do not consume paid captures.
Frequently Asked Questions
Is this exception unique to headless Chrome?
No. The exception describes the element’s current state. Headless mode can change layout or timing, but the documented diagnosis is to verify the element, action, visibility, timing, and obstruction first.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Should I remove the --headless argument?
Use headed mode as a comparison while diagnosing, not as the permanent fix. Keep headless after correcting the underlying selector, state, viewport, or synchronization issue.
Why did the error change to ElementClickInterceptedException?
That usually means Selenium reached the target but another element covered its center point. Investigate overlays, sticky navigation, modals, and animations separately.
What does readyState=complete guarantee?
It indicates that the navigation lifecycle reached that state; it does not guarantee that JavaScript has rendered, revealed, or enabled the control your next action needs.
Quick Recap
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.

