Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Use page.locator(...).filter(predicate) to narrow a useful set of candidate elements to the one you intend to interact with. For example, locate buttons, filter them by their exact textContent, and click the resulting locator. The filter callback runs in the browser—not in Node.js—so it cannot use ordinary Node-scope variables unless you serialize their values into the callback.
Filter a locator by a condition
Puppeteer recommends locators for selecting elements and interacting with them. Start with a selector that describes a meaningful candidate set, then use .filter() for the condition that distinguishes the target:
As an Amazon Associate I earn from qualifying purchases.
await page
.locator('button')
.filter(button => button.textContent === 'My button')
.click();
This is the pattern in Puppeteer’s “Page interactions” guide. It is not a rule that every page should be filtered by button text: choose a candidate selector and condition that fit the page’s markup and the distinction you need.
Runnable example
The following CommonJS script launches a browser, opens a page, filters buttons by exact text, clicks the matching locator, and closes the browser. Replace the URL and button text with values for the page under test; install Puppeteer in the project first.
#1 Best Overall
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
await page.goto('https://example.com');
await page
.locator('button')
.filter(button => button.textContent === 'My button')
.click();
} finally {
await browser.close();
}
})();
Use a real page with a button whose text is exactly My button; the example domain is only a URL to replace, not a page guaranteed to contain that button. The exact comparison distinguishes the complete textContent string, including any whitespace in the DOM text. If the page includes nested elements or variable whitespace, inspect the actual text and choose a predicate that expresses the intended condition.
Pass Node.js values into the filter safely
A filter callback executes in the browser context. It does not close over variables in your Node.js program, so a callback that refers directly to a Node variable may fail because that variable is not defined in the page.
Rank #2
For a value computed in Node, Puppeteer’s guide demonstrates constructing a callback string with the value serialized by JSON.stringify:
const buttonName = 'My button';
await page
.locator('button')
.filter(`button => button.textContent === ${JSON.stringify(buttonName)}`)
.click();
Serialization matters: inserting a raw string into executable JavaScript can produce invalid code or change its meaning when the value contains quotes or other special characters. Keep the callback logic intentional; JSON.stringify safely represents the value, but it does not make arbitrary callback code trustworthy.
Understand filtering, retries, and click checks
.filter(predicate) refines a locator by an expectation. It is not JavaScript’s Array.filter(): it does not immediately return an in-memory array of elements. Puppeteer documents that it retries when the expectation does not match, and locator actions are retried when the locator is not ready.
For a click(), the Page interactions guide documents automatic checks including that the element is in the viewport, visible, enabled, and has a stable bounding box across two animation frames. These checks help with changing pages, but they do not prove that your predicate identifies the intended unique element. Make the candidate selector and condition specific enough for the page.
Rank #4
Choose between filtering and selector syntax
Prefer the most direct selector that expresses stable user-facing meaning. Add a predicate when it clarifies a condition that the selector alone does not express. Puppeteer documents several selector forms; the clearest choice depends on the target and the page.
Free tools Windows power users keep installed
One-click scans. No signup required.
| Approach | Use it when | Important detail |
|---|---|---|
| CSS selector | A stable tag, class, attribute, or DOM relationship identifies the candidates. | Puppeteer selector APIs accept CSS selectors. |
.filter(predicate) |
You can locate candidates easily, but a condition such as exact textContent distinguishes the target. |
The predicate runs in the browser context; Node variables are not captured automatically. |
| Text selector | Visible text is a useful representation of the target. | Puppeteer text selectors choose minimal elements containing the requested text and can search open shadow roots. Escape selector-sensitive characters as the guide describes. |
| ARIA selector | The computed accessible role and name describe the target well. | Puppeteer computes these from the accessibility representation and resolves relationships such as labelledby. |
| XPath | The desired DOM relationship is more directly expressed with XPath. | Puppeteer uses the browser’s native Document.evaluate. |
| Shadow-DOM combinator | The target is inside an open shadow root. | >>> searches descendants at any depth; >>>> searches the immediate shadow root. The documented combinators have open-shadow-root and selector-depth limitations. |
These are alternatives, not a universal reliability ranking. Use the selector syntax that best conveys what makes the element the right one.
Best Value
Keep the locator in the right page or frame
page.locator(...) creates a locator on that page. If the target is in a frame, use the frame’s locator entry point, such as frame.locator(...), so the locator is scoped to the document containing the element.
Legacy selector prefixes
Prefixes such as text/My text, aria/My label, and xpath///h2 remain supported in the guide, but the current guide recommends its documented selector syntax. The legacy prefix form runs one non-CSS selector at a time and cannot combine selectors.
Troubleshoot a filter that does not find or click the target
- The callback reports an undefined variable: it likely refers to a Node.js variable from inside the browser-context predicate. Serialize the value into a callback string with
JSON.stringify, or use a selector that avoids passing that value. - The predicate keeps failing to match: check the candidate selector, the element’s actual
textContent, whitespace, and whether the page has finished rendering the target. The filter expectation is retried; a condition that never becomes true will not resolve to the intended element. - The click cannot proceed: inspect whether the target is in the viewport, visible, enabled, and stable, which are among the documented click checks. Also verify that the locator points to the correct page or frame.
- A text or ARIA selector behaves unexpectedly: confirm that the page’s visible text or computed accessible role and name match your selector, and escape selector-sensitive characters where the guide requires it.
- You are reaching for a lower-level API: Puppeteer also documents
page.waitForSelector()andElementHandle. They can be useful when the locator API lacks an operation you need, butwaitForSelector()does not automatically retry an action after that action fails. Dispose of returned element handles when finished to avoid memory leaks.
Or skip the browser setup
If your goal is to capture a page image or PDF rather than interact with a page element, ScreenshotNeo offers a screenshot API. Its clean-shot options accept cookie or consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses report the page verdict and billing status in headers. ScreenshotNeo also provides an MCP server with take_screenshot, get_page_info, and capture_pdf tools for AI agents.
Recommended Free Tools
One GET request captures a URL. For example, using cURL:
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 request options. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Sign up for ScreenshotNeo’s free plan.
Frequently Asked Questions
Which Puppeteer version do these documented behaviors refer to?
The cited official Puppeteer documentation pages display version 25.12.0. Check the documentation matching your installed version, since behavior and documentation can change.
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.




