How to click a link with a specific text with Puppeteer

By

Learn how to click a link or button by its text in Puppeteer 25 using page.locator with text or XPath selectors, handy for a cookie Accept all button.

~~~

To click a link with a specific text in Puppeteer, use a locator with a text selector. I wanted to click an “Accept all” cookie button, and today this is all it takes:

await page.locator('::-p-text(Accept all)').click()

::-p-text() is a Puppeteer-specific selector. It matches the deepest element that contains that text, whatever its tag is, so it works for an a and for a button alike. The locator waits for the element to show up and to be clickable, then clicks it.

When I first wrote this post, in 2023, I used an XPath query with page.$x():

const [linkcookie] = await page.$x("//a[contains(., 'Accept all')]")
if (linkcookie) {
  await linkcookie.click()
}

That no longer works. page.$x() and page.waitForXPath() were removed in Puppeteer 22 (February 2024). If you still prefer XPath, you can run the same expression through a locator:

await page.locator('::-p-xpath(//a[contains(., "Accept all")])').click()

Why not a plain CSS selector? CSS selectors can target ids, classes, and attributes, but they can’t select an element by its text. Text selectors and XPath can.

Let’s decode the XPath expression. //a finds all a elements anywhere in the document. The [contains(., "Accept all")] part filters them, keeping only the ones whose text contains “Accept all”. The dot means “the text of this element, including nested children”, so it still matches when the label is wrapped in a span inside the link.

Note that with XPath, if the button is a button HTML element (it depends on the HTML markup used), you have to use

await page.locator('::-p-xpath(//button[contains(., "Accept all")])').click()

instead. ::-p-text(Accept all) does not have this problem, because it does not care about the tag.

Open the page in your browser DevTools and inspect the element to see which tag the site uses.

The pitfall: the banner appears late

Cookie banners are often injected by a script after the initial page load. If you query the DOM too early, you find nothing, even though the button shows up a moment later.

Locators handle this for you. .click() polls the page until the element exists, is visible and is enabled, and only then clicks it. If the banner never appears, the call fails with a timeout error after 30 seconds by default. You can change that per locator:

await page.locator('::-p-text(Accept all)').setTimeout(5000).click()

One more thing: the match is case sensitive. 'Accept all' will not match a button labeled “Accept All”. Check the exact text in the page markup before blaming the code.

Also see my full Puppeteer tutorial.

Tagged: Node.js · All topics

Want me to talk about your product? You can sponsor this site.

~~~

Related posts about node: