Skip to main content

How to find by XPath text that contains apostrophe (single quote) in Selenium WebDriver

How to find by XPath text that contains apostrophe (single quote) in Selenium WebDriver

To escape a single quote (apostrophe) in XPath, you don’t escape it at all: XPath 1.0, the version browsers and Selenium WebDriver use, has no escape character inside a string literal. Wrap the text in double quotes instead, //button[text()="We'll be back"]. If the text contains both an apostrophe and a double quote, build the string with concat(). In Java, Selenium’s own Quotes.escape() does this for you.

Key takeaways

  • An apostrophe inside a single-quoted XPath literal ends the string early, so the whole expression is invalid and Selenium throws InvalidSelectorException.
  • Wrap the literal in double quotes instead. In Java source that means \" around it.
  • Use concat() when the text contains both quote characters. Quotes.escape() in selenium-support generates it.
  • \' and '' do not work in browser XPath. Check for a curly apostrophe (’) in the page text too.

Why does an apostrophe break an XPath expression?

XPath 1.0 defines a string literal as any run of characters between two double quotes, or between two single quotes, and nothing else. There is no backslash escape and no doubled-quote escape. So in //button[text()='We'll be back'] the literal is 'We', and ll be back'] is a syntax error. The expression is invalid, not just unmatched.

In Selenium 4 that surfaces as an exception:

// Throws org.openqa.selenium.InvalidSelectorException
driver.findElement(By.xpath("//button[text()='We'll be back']"));

We ran this exact call with Selenium 4.51.0 against headless Chrome, and it threw InvalidSelectorException. findElements() throws the same way rather than returning an empty list, because the selector itself is rejected.

How do you write the XPath with double quotes in Java?

Swap the quote character around the literal. Java strings are already delimited by double quotes, so the inner ones need a backslash in the Java source. The backslash is Java syntax and never reaches the XPath engine:

WebElement button = driver.findElement(By.xpath("//button[text()=\"We'll be back\"]"));

List<WebElement> matches = driver.findElements(By.xpath("//button[contains(., \"We'll\")]"));

The same rule works for attributes, for example //input[@placeholder="Don't type here"].

When the visible text is split across child elements, as in <a><span>Today's</span> deals</a>, text() only sees the direct text node and the match fails. Compare the full string value instead, with normalize-space() or .:

driver.findElement(By.xpath("//a[normalize-space()=\"Today's deals\"]"));

Older versions of this article used @text. That attribute exists in Appium’s Android page source, not in HTML. On a web page, visible text is a text node, so use text(), . or normalize-space().

What if the text has both single and double quotes?

Neither quote character can wrap a string that contains both, so split the string and glue the pieces together with concat(). Each piece goes in whichever quote it does not contain:

She said "it's fine"
concat('She said "it', "'", 's fine"')

In Java you don’t have to write this by hand. org.openqa.selenium.support.ui.Quotes, part of the selenium-support module that ships with selenium-java, returns a valid literal for any input:

import org.openqa.selenium.support.ui.Quotes;

String label = "She said \"it's fine\"";
WebElement button = driver.findElement(
    By.xpath("//button[normalize-space()=" + Quotes.escape(label) + "]"));

Quotes.escape() returns "We'll" for We'll, 'say "hi"' for say "hi", and a concat() expression when both characters are present. It adds the surrounding quotes itself, so don’t add your own. Selenium uses it internally for Select.selectByVisibleText(), which is why selecting a dropdown option such as Men's shoes works without any escaping on your side.

Escaping XPath quotes in Python

The Python bindings keep their equivalent private (Select._escape_string), so write a small helper:

def xpath_literal(s):
    if "'" not in s:
        return f"'{s}'"
    if '"' not in s:
        return f'"{s}"'
    parts = s.split("'")
    return "concat(" + ", \"'\", ".join(f"'{p}'" for p in parts) + ")"

driver.find_element(By.XPATH, f"//button[normalize-space()={xpath_literal(label)}]")

Selenium 4 removed the find_element_by_xpath() style helpers, so use find_element(By.XPATH, ...) as above.

What does not work

We checked each of these in Chrome’s own XPath engine (document.evaluate) and in libxml2’s xmllint. All three fail with a syntax error:

AttemptWhy it fails
'We\'ll be back'XPath has no backslash escape. The backslash is an ordinary character.
'We''ll be back'Doubling the quote is an XPath 2.0 rule. Browsers implement XPath 1.0.
'We'll be back'The apostrophe closes the literal.

&apos; only helps when the XPath sits inside an XML attribute, as in XSLT, because the XML parser decodes it before XPath sees the string. A Selenium locator is a plain string, so the entity is passed through literally and matches nothing.

Why does the XPath still find nothing?

If the expression is valid but returns no element, check the apostrophe on the page. Many CMSs and design tools convert ' to the typographic right single quote ’ (U+2019), and "We'll" does not match We’ll. Copy the text from the DOM in DevTools rather than from the screen, or normalize it in the expression:

//button[translate(text(), '’', "'")="We'll be back"]

If the element is added after page load, the locator can be right and the lookup still too early. Wrap it in an explicit wait in Selenium WebDriver before you start rewriting the XPath.

For links, By.linkText("Today's deals") and By.partialLinkText(...) take the text as a plain Java string with no XPath quoting at all, which is often the easier route. The guide to clicking a link by its text covers both, and selecting a dropdown option by visible text shows the Select class mentioned above. A stable id or a dedicated test attribute avoids the text match, and the quoting problem, entirely.

After the functional tests pass

Selenium tells you a page works for one user. LoadFocus checks the other side: load testing runs the same pages and APIs with many concurrent users from 25+ cloud regions, and visual regression testing finds visual differences between two versions of a page.

Frequently Asked Questions

How do you escape a single quote in XPath?

You can’t escape it inside a single-quoted literal in XPath 1.0. Put the text in double quotes instead, for example //p[text()="It's here"]. If the text has both quote types, build it with concat().

Why does my XPath break on an apostrophe?

The apostrophe closes the string literal early when you have wrapped the text in single quotes. The rest of the expression is then invalid, so Selenium throws InvalidSelectorException rather than returning no match.

Does a backslash or a doubled quote work in Selenium XPath?

No. Browsers implement XPath 1.0, which has neither. A doubled quote ('') is valid only in XPath 2.0 and later, which browsers do not support.

What if the text has both quote characters?

Use concat() to join pieces, each wrapped in the quote it does not contain. In Java, Quotes.escape() from selenium-support builds the expression for you.

Why does the XPath still find nothing after the fix?

The page may use a curly apostrophe (’) rather than a straight one (’), the text may be split across child elements so text() misses it, or the element may not be loaded yet. Check the DOM text in DevTools and use normalize-space() and an explicit wait.

Sources

Bogdan

Founder at LoadFocus

Bogdan builds and runs the tools this blog is about. He writes from what the products actually do in production, including the parts that break.

Weekly tips right in your inbox.

Don’t miss out on the latest testing tips and tricks, tools and news related to software testing.

Already +20,000 members in the list.

The Load Testing Platform with AI That Explains Your Results

Load test websites and APIs from 25 cloud regions, monitor page speed and uptime, and get AI analysis that explains your results in plain English.

Cloud load testing, website speed and API monitoring in one place.

Hi there! Can I share a cool thing I'm working on with you?

A software testing newsletter that sparks joy.

Our goal is to create helpful content for software developers and testers.

If you're not into it, you can unsubscribe instantly.