How to Fix Selenium Element Is Not Clickable at Point Exceptions
Fix Selenium click failures by inspecting the intercepted target, correcting page state, and using waits or scrolling where appropriate.
Short answer: “Element is not clickable at point” usually means the browser driver’s click location is blocked or affected by the page’s current layout or scroll state. Read the full exception, inspect the element named as the click recipient, resolve the obstruction or wait for the interface to be ready, then retry with Selenium’s normal element click. The message alone does not prove the cause in your test.
In newer Selenium exceptions, this is commonly reported as ElementClickInterceptedException. Start with the actual failed page state rather than adding a longer sleep or immediately switching to JavaScript.
1. Read the exception and identify what received the click
Capture the full exception text and inspect the browser at the failure point. If the message says another element would receive the click, that element is your first clue. It might be a dialog, cookie banner, sticky header or footer, toast, backdrop, or another overlay. Katalon’s troubleshooting guidance recommends removing an object covering the target before clicking it.
from selenium.common.exceptions import ElementClickInterceptedException
try:
driver.find_element(By.CSS_SELECTOR, "button.save").click()
except ElementClickInterceptedException as exc:
print(exc)
driver.save_screenshot("click-failure.png")
raise
In a failure hook, also record the current URL and relevant application state. A screenshot helps distinguish a true overlay from a wrong locator or a layout that shifted between locating and clicking.
2. Fix the page state before clicking
If the covering interface is expected, interact with it as a user would: close the dialog, accept or reject the consent prompt, or complete the preceding action that removes it. If it is transient, wait for the specific blocker to disappear or for the target to be ready. Do not wait for an unrelated fixed duration and assume that the click is now safe.
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, 10)
# Example: dismiss a known dialog, if present.
close = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button.dialog-close")))
close.click()
# Wait for the blocker to be removed, then click the target normally.
wait.until(EC.invisibility_of_element_located((By.CSS_SELECTOR, ".dialog-backdrop")))
target = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button.save")))
target.click()
Change the selectors to match the application. If the dialog is optional, handle its presence explicitly rather than making every run wait for it:
from selenium.common.exceptions import TimeoutException
try:
close = WebDriverWait(driver, 2).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "button.dialog-close"))
)
close.click()
WebDriverWait(driver, 5).until(
EC.invisibility_of_element_located((By.CSS_SELECTOR, ".dialog-backdrop"))
)
except TimeoutException:
pass # No dialog appeared within the short optional-dialog window.
target = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "button.save"))
)
target.click()
Use a short timeout for optional UI and a separate, reasonable timeout for required UI. Avoid swallowing timeouts for required steps: they should fail clearly when the expected page state never arrives.
3. Verify that Selenium found the intended control
A locator can match a hidden duplicate used by a responsive layout, an offscreen menu item, or a stale element from an earlier render. Check that the selected element is the visible intended control and that it is enabled. “Clickable” waits generally check visibility and enabled state; they do not establish that no other element covers the click point.
matches = driver.find_elements(By.CSS_SELECTOR, "button.save")
print("matches:", len(matches))
for index, element in enumerate(matches):
print(index, "displayed:", element.is_displayed(), "enabled:", element.is_enabled())
# Prefer a locator scoped to the correct visible form or dialog.
form = driver.find_element(By.CSS_SELECTOR, "form#profile")
target = form.find_element(By.CSS_SELECTOR, "button.save")
print("chosen control:", target.is_displayed(), target.is_enabled())
If several matches exist, scope the selector to the relevant form or container, or use a locator that identifies the active control. Re-find the element after navigation, rerendering, or opening a dialog instead of relying on an old reference.
4. Check scroll position, sticky elements, and layout changes
An offscreen element or a control positioned underneath a sticky header can fail even when its locator is correct. Scroll it into view, then retry the ordinary WebDriver click. The exact result can vary with the browser, driver, Selenium binding, and page layout.
target = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "button.save")))
driver.execute_script(
"arguments[0].scrollIntoView({block: 'center', inline: 'nearest'});",
target,
)
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button.save"))).click()
Centering the target can reduce overlap from fixed headers or footers, but it is not a universal fix. If the page animates or reflows after scrolling, wait for that change to finish and locate the target again. Selenium issue #16345 documents one specific scroll/click report with Selenium 4.35.0 Java bindings and Chrome/Chromium 139–140, including headed and headless runs. It is evidence for checking versions and reproductions, not proof of a universal Selenium defect.
5. Use JavaScript click only when DOM activation is intended
Executing arguments[0].click() can activate the DOM element without following the same browser hit-testing path as a user-facing WebDriver click. Katalon documents it as a workaround for click failures. Use it only when DOM-level activation matches what the test is meant to verify; it can allow a test to pass while a real user still cannot reach the control.
target = driver.find_element(By.CSS_SELECTOR, "button.save")
driver.execute_script("arguments[0].click();", target)
For tests of user workflows, first fix the overlay, locator, enabled state, scroll position, or timing, and keep the normal target.click().
6. Complete minimal examples in other languages
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;
public class ClickExample {
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
try {
driver.get("https://example.com/form");
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
By backdrop = By.cssSelector(".dialog-backdrop");
By close = By.cssSelector("button.dialog-close");
By save = By.cssSelector("button.save");
try {
WebElement closeButton = new WebDriverWait(driver, Duration.ofSeconds(2))
.until(ExpectedConditions.elementToBeClickable(close));
closeButton.click();
wait.until(ExpectedConditions.invisibilityOfElementLocated(backdrop));
} catch (org.openqa.selenium.TimeoutException absent) {
// The dialog is optional in this example.
}
WebElement target = wait.until(ExpectedConditions.elementToBeClickable(save));
target.click();
} finally {
driver.quit();
}
}
}
Python
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
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()
try:
driver.get("https://example.com/form")
wait = WebDriverWait(driver, 10)
try:
WebDriverWait(driver, 2).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "button.dialog-close"))
).click()
wait.until(EC.invisibility_of_element_located((By.CSS_SELECTOR, ".dialog-backdrop")))
except TimeoutException:
pass # Optional dialog did not appear.
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button.save"))).click()
finally:
driver.quit()
JavaScript (Node.js)
const { Builder, By, until } = require('selenium-webdriver');
(async function run() {
const driver = await new Builder().forBrowser('chrome').build();
try {
await driver.get('https://example.com/form');
const close = By.css('button.dialog-close');
const backdrop = By.css('.dialog-backdrop');
const save = By.css('button.save');
try {
const closeButton = await driver.wait(until.elementIsEnabled(
await driver.findElement(close)
), 2000);
await closeButton.click();
await driver.wait(async () => {
const elements = await driver.findElements(backdrop);
return elements.length === 0 || !(await elements[0].isDisplayed());
}, 5000);
} catch (error) {
if (error.name !== 'TimeoutError' && error.name !== 'NoSuchElementError') throw error;
}
const target = await driver.wait(until.elementLocated(save), 10000);
await driver.wait(until.elementIsVisible(target), 10000);
await driver.wait(until.elementIsEnabled(target), 10000);
await target.click();
} finally {
await driver.quit();
}
})();
Replace the example URL and selectors with those from your application. These examples use explicit state checks and retain a normal WebDriver click so interception remains visible as a test failure when the obstruction persists.
7. Troubleshooting common causes
| Symptom | Likely cause to investigate | Practical fix |
|---|---|---|
| Exception names a dialog, banner, or backdrop | Another element occupies the click point. | Dismiss the UI through its intended control, then wait for the blocker to disappear. |
| Target is enabled but click is intercepted | Visibility and enabled state do not rule out an overlay. | Inspect the reported recipient and page screenshot; wait for or remove the actual blocker. |
| Only some runs fail | A transient animation, toast, or asynchronous layout change may overlap the target. | Wait for the specific transition or blocker condition, not a guessed fixed sleep. |
| Wrong item is clicked or no item is usable | Locator matches a hidden duplicate or the wrong responsive region. | Count matches, inspect visibility, and scope the locator to the active form or container. |
| Failure follows scrolling | Sticky UI, reflow, or browser/driver-specific scroll behavior. | Center the target, wait for layout to settle, re-locate it, and record Selenium/browser/driver versions. |
| JavaScript click passes while normal click fails | DOM activation bypassed the user-facing hit-test obstruction. | Decide whether DOM activation is the intended test; otherwise fix the obstruction and retain WebDriver click. |
| Wait times out despite a long delay | Permanent overlay, wrong selector, disabled control, or absent page state. | Inspect the live DOM and complete exception; longer waits cannot resolve a permanent obstruction. |
8. Reliability, runtime, and maintenance
- Prefer condition-based waits. They proceed when the relevant state is reached and fail with a useful timeout when it is not. A fixed sleep adds delay on every run and still cannot fix a permanent overlay.
- Keep the click user-like when that is what you are testing. Normal WebDriver clicks expose a real obstruction; JavaScript activation may hide it.
- Make optional UI handling explicit. Short optional-dialog checks are reasonable, but do not ignore failures for required elements.
- Record reproducibility details. Save the exception, screenshot, browser and driver versions, Selenium binding version, viewport, and whether the run was headed or headless. This makes version- or layout-specific behavior easier to isolate.
- Account for rendering variance. Viewport size, responsive breakpoints, animation, and asynchronous content can change which element covers a point. Set a deliberate viewport where the test requires one and verify the actual page state.
9. Or skip the browser setup
If the task is to inspect or capture the page rather than test an interactive user flow, a screenshot API can avoid setting up and maintaining a browser session. [ScreenshotNeo](https://screenshotneo.com) is a website screenshot API and MCP server for developers. A GET request returns an image or PDF; see the [API documentation](https://screenshotneo.com/docs/) for request options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://example.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await require('node:fs/promises').writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
Cookie and consent banners are accepted and removed before capture, along with known newsletter popups and chat widgets; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server includes take_screenshot, get_page_info, and capture_pdf for AI agents. The free plan includes 1,000 shots a month with no card; paid plans start at $5 for 3,000 shots, and every feature is on every plan.
Sign up for 1,000 free screenshots a month, with no card required.
10. FAQ
Is “element is not clickable at point” the same as ElementClickInterceptedException?
It is commonly associated with the newer ElementClickInterceptedException wording. Use the complete message and page state to determine what happened in a specific run.
Does an element-to-be-clickable wait guarantee that clicking will work?
No. Visibility and enabled state do not prove that another element is not covering the click point.
Should I always use JavaScript to click?
No. Use it only when DOM-level activation is what the test intends, because it can bypass the obstruction a user would face.
Can a bigger window fix the problem?
It may alter responsive layout or scroll behavior, but it cannot reliably remove a persistent overlay or correct a wrong locator. Check the actual rendered state.


