Key takeaways
driver.findElements(By.tagName("a"))returns every anchor on the page, including hidden ones and ones with no destination.getAttribute("href")gives the resolved absolute URL; filter outnull, empty,javascript:,mailto:andtel:values before using the list.- Do not click through the list in a loop: every
click()plusback()makes the stored elements stale. Collect the URLs first, then visit or request them.
To find all the links on a web page with Selenium WebDriver in Java, call driver.findElements(By.tagName("a")). It returns a List<WebElement> with one entry per <a> tag, and you read each link’s URL with getAttribute("href") and its text with getText(). The examples below are written for Selenium 4 and compile against 4.51.0.
How do you get all the links on a page with Selenium?
Selenium 4.6 and later ships with Selenium Manager, which downloads a matching browser driver on its own. You no longer download chromedriver and set webdriver.chrome.driver; new ChromeDriver() is enough. Add org.seleniumhq.selenium:selenium-java to your Maven or Gradle project and run this:
import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
WebDriver driver = new ChromeDriver();
try {
driver.get("https://example.com/");
List<WebElement> allLinks = driver.findElements(By.tagName("a"));
System.out.println("Links found: " + allLinks.size());
for (WebElement link : allLinks) {
System.out.println(link.getText() + " -> " + link.getAttribute("href"));
}
} finally {
driver.quit();
}
findElements never throws when nothing matches; it returns an empty list. findElement (singular) returns only the first match and throws NoSuchElementException when there is none. The old findElementsByTagName helpers from Selenium 3 were removed in Selenium 4, so use the By form shown above.
The list includes anchors that are not visible, because findElements does not filter on visibility. If you only want links a user can see, add link.isDisplayed() to the loop condition.
How do you read the URL of each link?
Use getAttribute("href"). Selenium’s Javadoc says it returns the property with that name if one exists and falls back to the attribute otherwise. For href the property is the absolute URL resolved against the page’s base URL, which MDN documents for HTMLAnchorElement.href. So a link written as <a href="/pricing"> comes back as https://example.com/pricing.
If you need the raw text from the HTML source, use getDomAttribute("href"), which returns the attribute and ignores the property. An anchor without an href (a placeholder, or one wired up by JavaScript) gives null from getAttribute("href") or "" depending on the browser driver, so check for both.
How do you filter and deduplicate the links?
Many pages repeat the same link in the header, body and footer, and some anchors are not web links at all. Collect the useful ones into a LinkedHashSet, which drops duplicates and keeps page order:
Set<String> urls = new LinkedHashSet<>();
for (WebElement anchor : driver.findElements(By.tagName("a"))) {
String href = anchor.getAttribute("href");
if (href != null && !href.isBlank()
&& !href.startsWith("javascript:")
&& !href.startsWith("mailto:")
&& !href.startsWith("tel:")) {
urls.add(href);
}
}
A CSS selector can do part of the filtering for you: driver.findElements(By.cssSelector("a[href]")) only returns anchors that have an href attribute. To limit the search to one area, locate the container first and search inside it, for example driver.findElement(By.id("main")).findElements(By.tagName("a")). For other ways to locate elements, see how to locate web elements with Selenium WebDriver, or the comparison of the fastest ways to find elements.
How do you check that every link works?
Request each URL with an HTTP client instead of the browser. It is much faster, and a status code tells you more than a page that happened to load. This version uses the java.net.http.HttpClient that ships with Java 11 and later, sends a HEAD request, and falls back to GET for servers that answer 405 Method Not Allowed or 501:
HttpClient client = HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(10))
.build();
List<String> broken = new ArrayList<>();
for (String url : urls) {
if (!url.startsWith("http")) {
continue;
}
HttpRequest head = HttpRequest.newBuilder(URI.create(url))
.method("HEAD", HttpRequest.BodyPublishers.noBody())
.timeout(Duration.ofSeconds(15))
.build();
int status = client.send(head, HttpResponse.BodyHandlers.discarding()).statusCode();
if (status == 405 || status == 501) {
HttpRequest get = HttpRequest.newBuilder(URI.create(url))
.GET().timeout(Duration.ofSeconds(15)).build();
status = client.send(get, HttpResponse.BodyHandlers.discarding()).statusCode();
}
if (status >= 400) {
broken.add(status + " " + url);
}
}
System.out.println("Broken links: " + broken);
Treat the result as a first pass. Some sites answer automated requests with 403 or 429 even though the link works in a browser, and a link behind a login needs the session cookies the browser holds. Anything flagged is worth opening by hand before you report it as broken.
Why does clicking every link in a loop fail?
The loop from the original version of this post looks fine and breaks on the second pass:
for (WebElement link : allLinks) {
link.click();
driver.navigate().back(); // the next link.click() throws StaleElementReferenceException
}
After back() the browser reloads the page, so the elements in allLinks refer to a DOM that no longer exists. Selenium’s troubleshooting guide lists navigating away, reloading and DOM changes as the causes of a StaleElementReferenceException, and the fix is to locate the element again. Two patterns work. The first is to visit the URLs you collected earlier:
String startPage = driver.getCurrentUrl();
for (String url : urls) {
driver.get(url);
System.out.println(driver.getTitle());
}
driver.get(startPage);
The second is to find the elements again on every pass and click by index:
int count = driver.findElements(By.tagName("a")).size();
for (int i = 0; i < count; i++) {
driver.findElements(By.tagName("a")).get(i).click();
driver.navigate().back();
}
Use the second only when the click itself is what you are testing, for example a link that runs JavaScript. If a click opens a new tab, switch to it first; the new tab guide covers window handles. If the links load late, wait for them with an explicit wait, as in how to use explicit and implicit waits in Selenium WebDriver, instead of sleeping.
How do you find links inside an iframe?
findElements only searches the current browsing context, so links inside an <iframe> do not show up until you switch into it. Switch by index, then return to the main page:
List<WebElement> frames = driver.findElements(By.tagName("iframe"));
for (int i = 0; i < frames.size(); i++) {
driver.switchTo().frame(i);
System.out.println(driver.findElements(By.tagName("a")).size());
driver.switchTo().defaultContent();
}
Links added by JavaScript after the page loads are another common gap. If your count is lower than what you see on screen, wait for the content to render before calling findElements.
How do you click one specific link?
When you need one link and not all of them, search by its visible text: driver.findElement(By.linkText("Pricing")).click(). See how to click a link by text in Selenium WebDriver for linkText, partialLinkText and their limits.
Where does performance testing fit in?
A link check tells you whether pages exist, not whether they hold up under traffic or load quickly. Once the links work, LoadFocus has a free website speed test to see how those pages perform, and cloud load testing to run them under many concurrent users.
Frequently Asked Questions
How do I get every link on a page in Selenium Java?
Call driver.findElements(By.tagName("a")). It returns every anchor on the page as a list of WebElement objects, which you can loop over with getAttribute("href") and getText().
Why do some links come back with no URL?
An anchor does not have to have an href. Placeholders and links driven by JavaScript have none, so getAttribute("href") returns null or an empty string. Filter those out before using the list.
How do I get only the visible links?
findElements returns hidden anchors too. Filter the list with isDisplayed(), or search inside the container that holds the links you care about.
What is the best way to check the links work?
Collect the URLs first, then request them with an HTTP client outside the browser. Clicking each link in the browser is slower, and it forces you to relocate the elements after every navigation.
Why do I get StaleElementReferenceException when I click all the links?
Navigating away and coming back reloads the DOM, so the elements you stored are no longer attached to it. Collect the URLs and visit them one by one, or locate the elements again on each pass.
Do I still need to download chromedriver?
No. Since Selenium 4.6, Selenium Manager downloads a matching driver when none is found, so new ChromeDriver() works without setup.
Sources
- Selenium Manager, selenium.dev/documentation/selenium_manager (October 2026)
- WebElement Javadoc, selenium.dev/selenium/docs/api/java/org/openqa/selenium/WebElement.html (October 2026)
- Selenium errors troubleshooting, selenium.dev/documentation/webdriver/troubleshooting/errors (October 2026)
- HTMLAnchorElement.href, developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement/href (October 2026)