For an interactive control, start with its role and accessible name: page.getByRole('button', { name: 'Sign in' }). For non-interactive content, use getByText(). Reach for labels, placeholders, alt text, titles, test IDs, CSS, or XPath when they express the target more clearly. Playwright calls these APIs locators; “selectors” is common shorthand. A good locator describes the element you mean, not just where it happens to sit in the DOM.
What Playwright means by a locator
A locator is a live description of how to find an element on the current page. Playwright resolves it when an action or assertion uses it, rather than treating it as a permanent reference to one node. The official documentation calls locators “the central piece of Playwright’s auto-waiting and retry-ability.” That matters when a page rerenders: Playwright can resolve the locator again against the updated page.
Locator choice and readiness are related but distinct. A locator should identify the intended element; action auto-waiting handles documented readiness checks. For example, before a click Playwright checks actionability, including whether the target is visible and enabled. Waiting cannot make a broad locator identify the correct one if several elements match. See Playwright’s locator guide and its best practices.
Choose a locator that matches the contract
Prefer a user-facing attribute when the test is meant to reflect what a person can perceive or do. Use a test ID when the team intentionally maintains it as a stable test contract. CSS and XPath remain available for cases where their specific query capabilities are useful, but they often express implementation structure rather than user intent.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
#1 Best Overall
| Locator | Use it when | Advantage | Caution |
|---|---|---|---|
getByRole(role, { name }) |
Targeting buttons, links, headings, checkboxes, and other accessible controls | Reflects how users and assistive technology perceive the page | Roles and accessible names must be expressed correctly; include a name to distinguish repeated roles |
getByText(text) |
Finding non-interactive content by its wording | Clear and close to what appears on the page | Whitespace is normalized, and substring matches may be broad |
getByLabel(text) |
Finding a form control through its associated label | Identifies the control in user-facing terms | Needs a meaningful associated label |
getByPlaceholder(text) |
The placeholder is the useful input identifier | Concise for placeholder-led inputs | Placeholder copy can change and should not replace a proper label |
getByAltText(text) or getByTitle(text) |
The image alt text or title attribute is the intended identifier | Uses the relevant semantic attribute | Only useful where that attribute is present and meaningful |
getByTestId(id) |
The team maintains explicit test IDs, or user-facing locators are unsuitable | Resists copy and role changes | Not user-facing; requires the team to maintain the test contract |
locator() with CSS |
A CSS-specific or structural query is needed | Flexible and familiar | Can encode DOM implementation details |
locator() with XPath |
A relationship is best expressed in XPath | Broad DOM query capability | Often structure-dependent; XPath does not pierce shadow roots |
These APIs and tradeoffs are described in the locator documentation and other locator documentation.
Use role and accessible name for controls
A role locator identifies an element by its accessible role, and its name option narrows the match to the accessible name. This usually makes intent clearer than selecting a button by tag or class:
await page.getByRole('button', { name: 'Sign in' }).click();
Provide the name when practical. A page can contain several buttons, and getByRole('button') alone may not say which one the test means. If the button’s accessible name is missing or incorrect, that can indicate an accessibility issue as well as a locator problem. Prefer correcting the page’s semantics when possible rather than hiding the problem with a structural selector.
Use text for non-interactive content
getByText() is useful for a paragraph, status message, or other content whose wording is the relevant contract. For example:
await expect(page.getByText('Welcome, John', { exact: true })).toBeVisible();
Text matching normalizes whitespace even with exact: true: repeated spaces collapse, line breaks become spaces, and leading or trailing whitespace is ignored. Exact matching limits broad substring matches, but it does not mean the original whitespace must match byte for byte. For an interactive control, prefer its role and accessible name instead of selecting it only by visible text.
Rank #2
Use labels and other meaningful attributes for forms and content
Labelled form controls
Use getByLabel() when the associated label is how a user identifies the input. This keeps the test tied to a meaningful form label and naturally exposes missing or ambiguous labels.
Placeholder, alt text, and title
Use getByPlaceholder() when placeholder wording is genuinely the useful identifier, but remember that placeholder copy can change and is not a replacement for a label. Use getByAltText() for an image whose alt text identifies it, and getByTitle() when a meaningful title attribute is the intended target. These locators cannot identify content reliably if the respective attribute is absent or unhelpful.
Use test IDs as an explicit test contract
By default, getByTestId() reads data-testid:
await page.getByTestId('directions').click();
A test ID is useful when visible wording or accessibility roles do not give a suitable stable target, or when the team deliberately agrees to maintain a test-specific identifier. It is less likely to break when copy or roles change, but it does not tell you what a user sees or can do. If your project uses a different attribute, such as data-pw, configure testIdAttribute in Playwright Test configuration or use the selector configuration API. The locator guide documents both approaches.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Narrow repeated components by meaning
When a page contains many similar cards, list items, or repeated controls, locate the container by meaningful content and then find the action inside it. Chaining keeps the action scoped to the relevant component:
const product = page.getByRole('listitem').filter({ hasText: 'Product 2' });
await product.getByRole('button', { name: 'Add to cart' }).click();
Here the item is identified by its content, and the button by its role and name. A locator can also be narrowed with a descendant locator. This is usually easier to understand and maintain than choosing the second button on the page or constructing a long path through nested elements. See the locator examples in Playwright’s documentation.
Use CSS or XPath deliberately
Playwright supports CSS and XPath through page.locator(). Prefixes make the intended query type explicit:
await page.locator('css=button').click();
await page.locator('xpath=//button').click();
Some unprefixed CSS and XPath forms are detected automatically. CSS is appropriate when a CSS feature or a particular structural relationship is the real requirement. XPath can express broad DOM relationships. In both cases, consider whether the query encodes an incidental detail of the current markup. A long chain of nth-child() selectors or an absolute XPath can fail after a redesign that leaves the user-visible behavior unchanged. XPath also does not pierce shadow roots. See Other locators for supported options and limitations.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Resolve ambiguity instead of hiding it
Actions that imply one target are strict: if multiple elements match, Playwright throws rather than guessing. That failure is useful information—the locator has not yet described a unique target.
- Add an accessible name to a role locator, or scope it to the relevant container.
- Filter a repeated component by meaningful text or a descendant locator, then locate the control within it.
- Use
.first(),.last(), or.nth(index)only when order itself is the intended contract.nth()uses a zero-based index.
Positional methods make a choice explicit, but they can quietly target a different element if the page order changes. Do not use .nth() merely to silence a strictness error; refine the locator unless position is genuinely what the test intends. Strictness and positional selection are covered in the locator guide and Locator API reference.
Handle dynamic lists carefully
locator.all() immediately returns the elements present at that moment; it does not wait for a changing list to finish loading. If the list is populated asynchronously, first wait for an appropriate condition that establishes the expected state, then enumerate it. Otherwise, the returned set can reflect a transient page state. The API behavior is documented in the Locator reference.
Rank #4
Troubleshoot locator failures
“Strict mode violation” or multiple matches
The locator matched more than one element for a single-target action. Include a role name, exact text where appropriate, or scope the locator to a uniquely identified parent. Use a positional method only if the position is part of the behavior under test.
Outdated 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 matchWindows 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 reinstallNo element found
Check that the page has reached the expected state and that the queried role, accessible name, label, text, or attribute actually exists. If the content appears asynchronously, wait for a meaningful locator or page condition before acting. Avoid changing to a broad CSS query before checking whether the original semantic locator exposed a page accessibility or wording issue.
Locator works until copy or layout changes
A text locator can legitimately change when visible copy changes; a CSS or XPath chain can change when markup is rearranged. Decide whether the test is intended to protect that wording, a user-accessible behavior, or a stable internal test contract, and select text, role/name, or test ID accordingly.
Action times out despite a match
A matching element is not necessarily actionable. It may not be visible or enabled, among other actionability conditions. Check the current page state and the intended target rather than assuming that changing selector syntax solves a readiness problem. Locator auto-waiting and actionability are explained in Locators and Best Practices.
List enumeration misses items
If a list is still changing, locator.all() can observe only the elements currently present. Wait for an application-specific completion condition or expected item before collecting the list; do not treat all() as a wait operation.
Recommended Free Tools
Or skip the browser setup
If you need a screenshot of a page to inspect its layout or debug a locator, ScreenshotNeo provides a website screenshot API and MCP server for developers. A single request returns a PNG, JPEG, WebP, or PDF; it is for visual inspection, not a replacement for choosing and validating Playwright locators.
For example, this cURL request captures a page as WebP; replace the example URL with the page you need and supply your API key. See the ScreenshotNeo API documentation for request options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
- Cookie and consent banners, newsletter popups, and chat widgets are removed before capture; each cleanup step can be turned off.
- Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed. Responses identify the page verdict and billing status in headers.
- An MCP server offers
take_screenshot,get_page_info, andcapture_pdffor Claude, Cursor, and other MCP clients. - The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. All features are on every plan.
Learn about ScreenshotNeo, or sign up for 1,000 free screenshots a month with no card.
Sources and version scope
The guidance here follows the official Playwright documentation accessed September 29, 2026: Locators, Other locators, Best Practices, and the Locator API reference. These sources support the locator recommendations above; this guide does not assign them to a particular package release.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minuteQuick 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.




