Free tools Windows power users keep installed
One-click scans. No signup required.
If a Selenium-controlled PhantomJS form passes client-side validation but produces no POST or navigation, validation is not proof that submission reached the server. First establish whether the submit button was clicked and the form’s submit handler ran; then check for JavaScript errors, canceled or AJAX submissions, and finally whether PhantomJS sent a request. For Selenium 4, clicking the actual enabled submit button is generally preferable to calling form.submit(). A workaround reported for one old PhantomJS setup may help that legacy stack, but it is not a general fix for current websites.
What “valid but not submitted” can mean
Form validation and form submission are separate stages. A browser can decide that the fields satisfy client-side constraints, then fail or stop before a request is sent. The cause may be a missing or mis-targeted click, a submit handler that calls preventDefault(), an exception in application code, an AJAX request that fails, navigation that does not occur, or a browser-side network or TLS problem.
Start by defining what “not submitted” means in your test. No page change alone is not proof that no request occurred: an application may submit in the background and update the page in place. Conversely, a form can look valid and still be stopped by an invalid control or application validation that is not reflected in the visible form state. Use request evidence, not a screenshot or a green validation message, to determine whether the server received anything.
Click the real submit button before trying form submission
Selenium treats clicking a control and submitting a form as different interactions. The Selenium project’s element-interactions guidance recommends clicking the applicable submit button rather than relying on the separate submit operation in Selenium 4, where the operation is implemented by executing a script. A click follows the page’s ordinary interaction path more closely: it targets the control the user would activate and allows the page’s click and submit handlers to run.
#1 Best Overall
Use a selector that identifies the intended form and its actual submit control. Check that the control belongs to that form, is displayed, and is enabled. Do not guess that the first button on the page submits the form; pages often contain multiple forms, buttons, or controls that look similar.
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
form = driver.find_element(By.CSS_SELECTOR, "form[name='login']")
submit = form.find_element(By.CSS_SELECTOR, "button[type='submit']")
WebDriverWait(driver, 10).until(lambda d: submit.is_displayed() and submit.is_enabled())
submit.click()
Adjust the selector and wait duration to the page and test. If the site uses an input[type="submit"], an image submit control, or a custom button, select the real control instead. If the form is inside an iframe, switch to that frame before locating it; a selector in the top-level document cannot locate elements in a different browsing context.
Rank #2
When a direct form submission is—and is not—appropriate
A form-level submit can be a useful diagnostic or a legacy fallback, but it is not interchangeable with clicking the button. Selenium’s submit operation applies to form elements; calling it on an element outside a form is a no-op in the JavaScript API documentation. More importantly, MDN documents that native form.submit() does not dispatch the form’s submit event. If the site registers its validation, analytics, or AJAX logic on that event, directly submitting the form can bypass the code the application needs.
# Fallback only after confirming that bypassing the submit event is safe.
form = driver.find_element(By.CSS_SELECTOR, "form[name='login']")
form.submit()
MDN also notes that invalid controls dispatch invalid events and prevent submission before a submit event is sent. So if you do not see a submit event, determine whether native validation blocked it or whether your test used a direct native submission path that skips the event. Where supported by the target browser, requestSubmit() preserves submit-event behavior more closely than submit(); do not assume an old PhantomJS version implements it. If the page depends on modern browser APIs, migration is safer than layering shims onto PhantomJS.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →Rank #3
Trace the failure in order
- Prove the target. Locate the intended form by a stable identifier or scoped selector, then locate its submit control inside that form. Confirm the button is enabled and displayed. Verify that Selenium is in the correct frame and window.
- Record the browser and driver. Check which PhantomJS binary is actually being launched, not just which version you expect. Legacy environments can have multiple installed versions. Record Selenium, PhantomJS, operating-system, proxy, and HTTPS/OpenSSL details alongside the failing test.
- Capture browser-side errors before clicking. PhantomJS provides
page.onErrorfor JavaScript syntax and runtime exceptions andonConsoleMessagefor console output. Its documentation warns that console output fromevaluateis otherwise not displayed. When using PhantomJS directly, set those handlers before loading the page. With Selenium controlling PhantomJS, use the logging hooks exposed by your particular driver or instrument the page; do not assume Selenium’s Python object gives direct access to PhantomJS’spagecallbacks. - Trace click and submit events. Add temporary event instrumentation before interacting, or use the browser’s debugging facilities. Check whether the intended button’s click occurs, whether a
submitevent follows, and whether application code cancels it withpreventDefault(). If the form is intentionally AJAX-driven, a canceled default navigation may be normal; the AJAX request is then the event to trace. - Look for the request. Use PhantomJS resource-request and response hooks when available, or an authorized test proxy. Record the request URL, method, response status, and redirects. If there is no request, continue with DOM, event, and JavaScript debugging. If a request exists, inspect its response, cookies, CSRF data, redirects, proxy behavior, and TLS errors.
- Only then try a legacy compatibility setting. For the historical PhantomJS case described below, test the two reported settings and verify the actual request. A changed screenshot or URL alone does not establish that a POST was sent or accepted.
- Reproduce on a maintained browser driver. If the page requires modern JavaScript, TLS, or browser APIs, repeat the test in a maintained Selenium browser setup. Current Selenium guidance centers on maintained WebDriver components; PhantomJS documentation and its compatibility behavior are legacy.
A small event trace for Selenium tests
This temporary browser-side probe records click, submit, cancellation, and uncaught JavaScript errors. Install it after the page and form are present but before clicking. It is diagnostic, not a substitute for observing network traffic.
driver.execute_script("""
window.__formTrace = [];
window.addEventListener('error', function (event) {
window.__formTrace.push({type: 'error', message: event.message});
});
document.addEventListener('click', function (event) {
if (event.target && event.target.closest) {
var button = event.target.closest('button, input[type=submit]');
if (button) window.__formTrace.push({type: 'click', name: button.name || '', id: button.id || ''});
}
}, true);
document.addEventListener('submit', function (event) {
window.__formTrace.push({type: 'submit', form: event.target.name || event.target.id || ''});
setTimeout(function () {
window.__formTrace.push({type: 'defaultPrevented', value: event.defaultPrevented});
}, 0);
}, true);
""")
# After the click and any expected asynchronous work:
trace = driver.execute_script("return window.__formTrace")
print(trace)
The delayed defaultPrevented check is only a clue: page code may handle submission asynchronously, and instrumentation cannot tell you whether an AJAX call succeeded. Also, closest() is not available in every older browser engine; if this probe itself throws, simplify the selector or use the browser’s debugging hooks. For older PhantomJS, do not infer that an absent trace proves the page did nothing—the browser may lack the APIs used by the probe.
Rank #4
The PhantomJS settings reported for the historical case
The report matching this problem used Selenium 1.43, PhantomJS 1.98, Python 2.7, and Ubuntu 14.04. Its accepted answer reported success after enabling phantomjs.page.settings.localToRemoteUrlAccessEnabled and phantomjs.page.settings.browserConnectionEnabled, then submitting the form element. Treat that as a version-specific workaround for a legacy environment, not as a universal setting for every PhantomJS driver or a recommended fix for current browsers.
The setting names belong to PhantomJS page configuration. How to apply them depends on how PhantomJS is launched and which driver wrapper is in use; do not paste them as arbitrary Selenium capabilities and assume they took effect. Confirm that the running PhantomJS page received both settings, then repeat the test while recording resource requests and browser errors. Keep the workaround only if it addresses the observed failure without hiding a real network or application error.
Best Value
Common symptoms and what to check
- Validation appears, but no submit event is logged: verify that the real submit button was clicked and that the form is not blocked by an invalid control. If your test called native
form.submit(), remember that this does not dispatch the submit event. - The submit event is logged, but no navigation occurs: inspect handlers for
preventDefault(). The page may be using AJAX; check request logs rather than expecting a URL change. - An error appears in PhantomJS’s error log: identify the script and line, then determine whether old PhantomJS lacks a browser API the page expects. Fixing a selector or adding a delay will not repair an unsupported API.
- The request appears but the test still fails: inspect status, redirects, cookies, CSRF requirements, and response body. A request being sent is not proof that the server accepted it.
- HTTPS behavior differs by machine: verify the actual PhantomJS binary and its HTTPS/OpenSSL support, and check proxy configuration and latency. PhantomJS troubleshooting documentation calls out multiple installed versions, HTTPS library problems, proxy latency, and resource/error logging.
- The test passes only after adding a long sleep: replace timing guesses with an explicit wait for a meaningful state, such as a success element, known URL change, or response condition observable to the test. A sleep can mask a race but cannot prove submission.
Or skip the browser setup
If the immediate need is a clean visual record of the form page rather than a test of whether its POST succeeded, ScreenshotNeo can capture a page without setting up a browser automation stack. It is a screenshot API, not a Selenium replacement: a screenshot cannot establish that a request was sent or accepted. Its API accepts one GET request with a URL and returns a PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API documentation for options and response details.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/login -o shot.webp
ScreenshotNeo accepts cookie/consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each of those steps can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed; response headers identify the page verdict and billing status. It also provides an MCP server with take_screenshot, get_page_info, and capture_pdf tools for AI agents. The Free plan includes 1,000 screenshots per 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.
Choosing a durable fix
| Approach | Submit-event behavior | Best use | Main limitation |
|---|---|---|---|
| Click the actual submit control | Follows the ordinary interaction path and lets page handlers run | Default choice when the test should behave like a user | Requires a correctly identified, enabled control and correct frame |
| Submit the form element | Native form.submit() does not dispatch the submit event |
Legacy fallback after confirming the page does not need submit listeners | Can bypass application logic; Selenium 4 guidance favors clicking |
| Apply the reported PhantomJS settings | Does not itself prove event flow or request success | Reproducing the matching old PhantomJS case | Historical, version-specific workaround; must verify network evidence |
| Move to a maintained browser driver | Depends on using the page’s real interaction path | Sites requiring current TLS, JavaScript, or browser APIs | Requires updating the test environment |
Frequently Asked Questions
Can a screenshot confirm that the form was submitted?
No. It can show the rendered page state, but it cannot prove whether a request was sent, what response the server returned, or whether the server accepted the submission.
Does a successful POST always mean the login or form action succeeded?
No. The server can reject the request or redirect to an error state. Check the response and resulting application state, not just the request method.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →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.

