Recommended Free Tools
Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Use a locator to identify the intended control, wait until it is ready, clear it when you mean to replace its current value, and call send_keys(). In Python, the dependable pattern is:
field = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.NAME, "username"))
)
field.clear()
field.send_keys("admin")
send_keys() works only with an editable text field or another keyboard-interactable element. Most failures come from an unstable or non-unique locator, interacting before the page is ready, or attempting to type into a control that is not editable.
What Selenium considers a text box
A conventional text box is usually an <input> element, while a multi-line box is commonly a <textarea>. Selenium does not require either tag specifically: send_keys() can target any element that accepts keyboard interaction. A disabled, read-only, hidden, or otherwise non-editable element cannot receive ordinary text input.
The interaction has five deliberate stages:
- Choose an attribute or relationship that identifies the intended field.
- Locate it with
find_element(). - Wait for the state your page requires, such as visibility.
- Call
clear()if existing text must be replaced. - Call
send_keys()with the value to enter.
Prerequisites and a minimal Python setup
Install Selenium in the environment that will run the test, have a browser and its compatible WebDriver available, and create a driver before locating fields. This minimal example uses Chrome:
#1 Best Overall
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome()
driver.get("https://example.com/login")
field = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.NAME, "username"))
)
field.clear()
field.send_keys("admin")
# Continue with the rest of the test, then release the browser.
driver.quit()
Replace the URL, locator, and value with those for your application. The explicit wait gives a dynamic page up to 10 seconds to expose a visible matching element; it does not make an incorrect locator correct.
Choose a locator that will survive UI changes
Python’s Selenium API supports ID, name, XPath, CSS selector, class name, tag name, link text, partial link text, and RelativeBy strategies. The best choice is the one that is unique, readable, semantically related to the field’s purpose, and unlikely to change during ordinary UI revisions.
| Strategy | Example | When it fits | Main risk |
|---|---|---|---|
| ID | (By.ID, "username") |
A stable, unique id identifies the control. |
Generated IDs can change between renders. |
| Name | (By.NAME, "username") |
The form’s name expresses the field’s purpose and is stable. |
Several controls may share a name. |
| CSS selector | (By.CSS_SELECTOR, "input[type='email']") |
You need a combination of attributes or a concise relationship. | A broad selector can match an unintended field. |
| XPath | (By.XPATH, "//label[normalize-space()='Username']/following::input[1]") |
The field must be reached through a visible relationship when no simple attribute is sufficient. | Long paths tied to layout are fragile. |
| Class name | (By.CLASS_NAME, "username-field") |
A distinctive class is dedicated to the control. | Styling classes often apply to multiple elements or change frequently. |
| Tag name | (By.TAG_NAME, "textarea") |
You intentionally need a tag-level match and know it is unique. | Most pages contain many inputs or textareas. |
| Link text or partial link text | (By.LINK_TEXT, "Edit profile") |
Useful for links that lead to a form, not usually for the input itself. | Copy changes and duplicate link labels break the match. |
| RelativeBy | driver.find_element(RelativeBy.with_tag_name("input").to_right_of(label)) |
A relative relationship is clearer than a long XPath. | The relationship can become ambiguous if the layout changes. |
find_element() returns the first matching element. Before typing, make sure that “first” is the field you mean; if you intentionally need every match, use find_elements() and handle the resulting list explicitly.
Wait for the state you actually need
Finding a DOM node and being able to type into it are different conditions. A single-page application may insert the input after navigation, replace it during rendering, or reveal it only after a panel opens. Use WebDriverWait with an expected condition rather than guessing with a fixed sleep.
Rank #2
Wait for visibility
field = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.ID, "search"))
)
field.send_keys("selenium")
Visibility is appropriate when the control must be present and displayed before typing. If your flow has a different prerequisite, wait for that state first and then locate or interact with the field.
Wait for text in a page element
WebDriverWait(driver, 10).until(
EC.text_to_be_present_in_element((By.ID, "status"), "Ready")
)
field = driver.find_element(By.ID, "search")
field.send_keys("selenium")
Text-presence checks are useful when a status message signals that a form has finished loading. Keep the condition tied to an observable state in your page instead of an arbitrary delay.
Handle a changing reference
If a framework replaces the input node after you locate it, the old element reference no longer represents the current page state. Wait for the replacement state and locate the field again immediately before typing. A locator that is unique and a condition that describes the rendered state reduce this class of failure.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Clear, then enter: replacement versus appending
send_keys("new value") adds keystrokes to the control; it is not an instruction to replace every character already present. When replacement is intended, call clear() first:
Rank #3
field = driver.find_element(By.NAME, "username")
field.clear()
field.send_keys("new value")
clear() resets an editable, resettable text-entry element. If you are testing an append operation, omit it deliberately and assert the resulting value instead of assuming what the field contained.
Confirm what was entered
For an input, the entered value is normally exposed through its value property. You can read it with JavaScript when a test needs an explicit check:
actual = driver.execute_script("return arguments[0].value", field)
assert actual == "new value"
This check distinguishes a locator or interaction problem from an application that transforms, masks, or rejects the submitted value.
Free tools Windows power users keep installed
One-click scans. No signup required.
Complete form example with robust synchronization
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome()
wait = WebDriverWait(driver, 15)
try:
driver.get("https://example.com/account")
username = wait.until(
EC.visibility_of_element_located((By.NAME, "username"))
)
username.clear()
username.send_keys("admin")
password = wait.until(
EC.visibility_of_element_located((By.ID, "password"))
)
password.clear()
password.send_keys("correct-horse-battery-staple")
# Keyboard submission is appropriate when the form treats Enter as submit.
password.send_keys(Keys.ENTER)
finally:
driver.quit()
Use test credentials and a test environment. If pressing Enter is not the application’s submission mechanism, locate the submit button with its own stable locator and click it instead.
Rank #4
Special cases that are often mistaken for text-entry failures
File inputs
A file input is a special control. Selenium’s Python API supports supplying a file path with send_keys() to the file input; do not try to type a human-readable filename into a separate visual label.
file_input = driver.find_element(By.NAME, "attachment")
file_input.send_keys("/absolute/path/to/report.pdf")
Read-only, disabled, or hidden controls
These controls are not ordinary keyboard targets. Check the element’s state and the page’s intended workflow. A read-only display may be populated by another action, while a disabled field may become editable only after a selection or permission change. Wait for that transition, then locate the now-interactable element.
More than one matching field
A generic selector such as every input can match search, login, and hidden controls at once. Narrow it by a stable ID, name, CSS combination, or meaningful relationship. If multiple matches are intentional, use find_elements(), inspect the collection, and choose by a documented rule rather than list position alone.
Java uses the same interaction model
The Java WebElement contract describes sendKeys(CharSequence...) as simulated typing and clear() as resetting a form-entry value. The sequence is therefore identical: locate, wait when necessary, optionally clear, then send keys.
Best Value
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
WebElement field = wait.until(
ExpectedConditions.visibilityOfElementLocated(By.name("username"))
);
field.clear();
field.sendKeys("admin");
Use the Java imports for your Selenium version, including Duration, WebDriverWait, ExpectedConditions, and WebElement.
Troubleshooting: symptom, cause, and fix
| Symptom | Likely cause | Fix |
|---|---|---|
send_keys raises an invalid element state error. |
The target is not editable or keyboard-interactable. | Locate the actual text field, wait until it is enabled and displayed, or follow the control’s workflow that makes it editable. |
| No text appears. | The locator matched the wrong element, or the page has not reached its interactive state. | Verify uniqueness, inspect the matched element, and add an explicit wait for visibility or the page state that precedes entry. |
| Old text remains before the new value. | send_keys appends keystrokes. |
Call clear() before typing when replacement is the requirement. |
| The script works intermittently. | It races a dynamic render or a node replacement. | Replace fixed sleeps with WebDriverWait and a condition such as visibility; locate the current element after the condition succeeds. |
| The wrong field receives input. | find_element returned the first of several matches. |
Use a more specific ID, name, CSS selector, XPath relationship, or RelativeBy expression; use find_elements when a collection is expected. |
| A file upload does not work. | The script is typing into a label or custom button rather than the file input. | Locate the file input and send it an absolute file path. |
Reliability and maintenance checklist
- Prefer a stable, unique attribute or semantic relationship over a positional selector.
- Keep the locator close to the interaction so a failed wait identifies the exact field.
- Use explicit waits for dynamic state; avoid making a fixed delay your synchronization strategy.
- Decide explicitly whether the test should append or replace, and use
clear()only for replacement. - After locating, verify the field’s type and state before calling
send_keys(). - When a page re-renders a form, locate the field again after the relevant condition succeeds.
- Use
find_elements()only when multiple matches are part of the test’s design.
Or skip the browser setup
If your goal is a clean image or PDF of a page rather than interactive form testing, ScreenshotNeo provides a single screenshot API request. It handles consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks or CAPTCHAs, 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 exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.
For a direct request, see the ScreenshotNeo API documentation:
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorscurl -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 supports full-page captures with lazy images loaded, CSS-selector element shots, dark mode, 12 device presets plus custom viewports, retina scale, PDF paper and page-range controls, custom CSS and JavaScript, pre-capture clicks, selector hiding, waits for a selector, delay, or network idle, request and resource blocking, custom headers, cookies, user agents and Authorization, timezone and geolocation, transparent backgrounds, resizing, selectable cache TTLs, signed links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API, an OpenAPI specification, and parameter names used by other screenshot APIs.
| Plan | Price | Included shots per month |
|---|---|---|
| Free | $0 | 1,000 |
| Starter | $5 | 3,000 |
| Growth | $15 | 15,000 |
| Pro | $39 | 60,000 |
| Scale | $99 | 250,000 |
| Business | $249 | 1,000,000 |
Every feature is included on every plan, yearly billing provides two months free, and the Free plan requires no card. If you need automated page images instead of browser-driven data entry, create a free ScreenshotNeo account to get 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.
Frequently Asked Questions
How do I know whether to use clear() in a test?
Use it when the test’s requirement is replacement of the current value. Omit it when appending is intentional, and verify the resulting value explicitly.
Can the same locator pattern be used for a multi-line field?
Yes. Locate the editable <textarea> (or another keyboard-interactable element), wait for the required state, and use the same optional clear() followed by send_keys() sequence.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →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.

