Playwright, Selenium, and Puppeteer are the three most popular browser automation tools. They can be used for end-to-end testing, web scraping, screenshot generation, and increasingly to enable AI agents to use the browser.
While Playwright and Puppeteer are architecturally similar, Selenium is an entirely different beast. In this article, we'll cover each tool's history, pros and cons, and main use cases. Additionally, we'll introduce Browser Use, an AI successor to traditional browser automation.
TL;DR
| If you need... | Use |
|---|---|
| Test automation | Playwright |
| Simple, Chromium-focused automation | Puppeteer |
| Legacy browser support | Selenium |
| Agentic workflows / sites that change often | Browser Use |
Selenium
Selenium is a pioneering framework for browser automation. It was started by Jason Huggins in 2004. Over time, the team behind Selenium developed multiple browser automation tools, including:
- Selenium IDE (2006) -- a browser extension that lets you record, edit, and play back interactions with websites and web apps.
- Selenium Grid (2008) -- allows running web tests in parallel across multiple machines, browsers, and operating systems at the same time.
- Selenium WebDriver (2011) -- formed the basis for the W3C WebDriver standard, which became a W3C Recommendation in 2018. Most major web browsers support it, including Chrome, Firefox, Safari, and Edge.
The Selenium WebDriver communication protocol looks something like this:

In 2020, Selenium began contributing to the W3C's WebDriver BiDi standard, which fills some gaps of the classic WebDriver and is intended to replace it in the future.
Selenium's main use cases include automated UI testing, regression testing, cross-browser testing, and web scraping.
The framework's main advantages are its W3C standard status, mature & extensive ecosystem, and support for legacy browsers. On top of that, the framework supports multiple programming languages, including Java, Python, C#, JavaScript, and Ruby.
Selenium's main downsides are that it doesn't provide the best developer experience (difficult to set up, lots of boilerplate code), adds performance overhead (classic WebDriver uses HTTP), and isn't the most elegant solution for modern web apps (e.g. SPAs).
To extract a page's <h1> tag with Selenium, you can use a script like this:
// selenium.js
const { Builder, By, until } = require("selenium-webdriver");
(async () => {
// Launch a new Chrome browser instance (via ChromeDriver)
const driver = await new Builder().forBrowser("chrome").build();
try {
// Navigate to the target page
await driver.get("https://browser-use.com/");
// Wait for h1 to appear in the DOM and for it to render
const h1 = await driver.wait(until.elementLocated(By.css("h1")), 10000);
await driver.wait(until.elementIsVisible(h1), 10000);
// Extract the visible text and log it
const text = await h1.getText();
console.log("H1:", text);
} finally {
// Close the browser (even if an error was raised)
await driver.quit();
}
})();Puppeteer
Puppeteer is a Node.js library for browser automation that Google created in 2017. The library was released right after Chrome shipped its headless mode. Unlike Selenium, which uses WebDriver, Puppeteer uses the Chrome DevTools Protocol (CDP) for Chrome and BiDi for Firefox automation.
Chrome DevTools Protocol is a low-level interface for inspecting and controlling the Chromium-based browsers. Compared with WebDriver, it is significantly faster because it uses a persistent WebSocket connection instead of HTTP requests. Moreover, it enables bidirectional communication.

BiDi is architecturally similar to CDP but vendor-agnostic.
The library is mostly used for scraping both traditional websites and SPAs, taking screenshots, PDF generation, and other browser automation tasks.
Puppeteer's main advantages include its performance, lightweightness, and its ability to leverage Chrome/Chromium-specific capabilities. These include network interception, browser debugging, performance monitoring, and device emulation.
On the other hand, Puppeteer also has a few disadvantages. Firstly, it is Chromium-centric (BiDi has a reduced API surface), has a smaller ecosystem than Selenium, and only supports JavaScript and TypeScript.
Here's the same exact script to extract the page heading in Puppeteer:
// puppeteer.js
const puppeteer = require("puppeteer");
(async () => {
// Launch a new Chrome browser instance
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
// Navigate to the target page
await page.goto("https://browser-use.com/");
// Wait for h1 to appear in the DOM and for it to render
const h1 = await page.waitForSelector("h1", {
visible: true,
timeout: 10000,
});
// Extract the visible text and log it
const text = await h1.evaluate((el) => el.textContent);
console.log("H1:", text);
} finally {
// Close the browser (even if an error was raised)
await browser.close();
}
})();Playwright
Playwright is a browser automation framework developed at Microsoft and open-sourced in January 2020. It was created by the same group of engineers who had previously worked on Puppeteer.
The framework adopted Puppeteer's best ideas and fixed its biggest gaps. It added support for Firefox and WebKit (via Playwright-specific browser builds), support for multiple programming languages (Python, .NET, and Java). It introduced auto-waits, browser contexts, codegen, trace viewer, and other powerful tooling.
Playwright's communication works similarly to Puppeteer. It uses CDP for Chromium-based browsers, and custom protocols for Firefox and WebKit:

The framework is most commonly used for test automation. This is mainly because of its built-in test runner and its ability to write clean, concise, maintainable tests. Other than that, the framework can also be used for scraping, and it has been increasingly adopted by AI browser agents.
Its downsides are fewer, but they exist. Firefox and WebKit are Playwright-specific builds rather than the browsers your users actually run; it doesn't support legacy browsers, and its ecosystem is younger and smaller than Selenium's. It is also somewhat opinionated.
Finally, the same heading-fetching script in Playwright:
// playwright.js
const { chromium } = require("playwright");
(async () => {
// Launch a new Chrome browser instance
const browser = await chromium.launch();
try {
const page = await browser.newPage();
// Navigate to the target page
await page.goto("https://browser-use.com/");
// Locator auto-waits for the element to appear when you act on it
const h1 = page.locator("h1").first();
// Extract the visible text and log it
const text = await h1.textContent();
console.log("H1:", text);
} finally {
// Close the browser (even if an error was raised)
await browser.close();
}
})();Browser Use
To automate a browser with traditional browser automation tools, you must describe the whole process in code. Browser Use, an open-source library for AI browser automation started in 2024, inverts that. Instead of describing the process in code, you describe the goal using natural language.
For example, you can provide these prompts to Browser Use agents:
- Book me the fastest flight from Bali to San Francisco on the 18th of September.
- Go to Wikipedia's page for the world's countries and extract the top 10 biggest countries'
name,area_km2andpopulationas valid JSON. - Search for the latest news about NVIDIA and summarize the three biggest stories.
To make it work, the library extracts the DOM into an indexed, text-like representation. It then uses an LLM to reason over it and determine how to perform the task. Historically, Browser Use used Playwright, but later migrated to raw CDP for faster, more capable automation.

Browser Use's main advantages are speed to a working automation, resilience to DOM changes that would break a hardcoded selector, and ease of use. Additionally, by opting into Browser Use Cloud you get built-in stealth and protection against bot detection.
The downsides are the same as those of every other AI-driven automation tool. Runs are non-deterministic (the same prompt can take different paths), each step costs an LLM call, and failures are harder to trace and debug.
Since Browser Use would be overkill for extracting an <h1>, let's demonstrate how to fetch top 5 HackerNews stories:
# browser-use.py
import asyncio
from browser_use import Agent, ChatAnthropic
from pydantic import BaseModel
# Define the shape of a single story
class Story(BaseModel):
title: str
points: int
# Wrap the stories in a list so the agent returns all 5 at once
class Stories(BaseModel):
stories: list[Story]
async def main() -> None:
# Describe the goal in natural language instead of in code
agent = Agent(
task="""
Find the top 5 HN stories.
Return only {"stories": [{"title": "..." , "points": 0}, ...]}.
""",
llm=ChatAnthropic(model="claude-sonnet-5"),
# Force the agent's final output to match the schema above
output_model_schema=Stories,
)
# Let the agent navigate and extract on its own
history = await agent.run()
# Parse the final result and print each story
stories = Stories.model_validate_json(history.final_result() or "{}")
for story in stories.stories:
print(story)
if __name__ == "__main__":
asyncio.run(main())Conclusion
In this article, we've looked at the most popular browser automation libraries.
As a rule of thumb, use Playwright for test automation because of its extensive tooling. Puppeteer for simple Chrome automations, Selenium if you require legacy browser support, and Browser Use for agentic workflows or when working with websites that change frequently.
Finally, I've summarized the differences down below:
| Selenium | Puppeteer | Playwright | Browser Use | |
|---|---|---|---|---|
| Main use | Cross-browser testing | Scraping, screenshots, PDFs | Test automation | Agentic workflows |
| Browsers | All major + legacy | Chrome, Firefox | Chrome, Firefox, WebKit | Chrome |
| Languages | Java, Python, C#, JS, Ruby | JS, TS | JS, TS, Python, .NET, Java | Python |
| Protocol | WebDriver | CDP (Chrome), BiDi (Firefox) | CDP + custom | CDP |
| Pros | W3C standard, mature ecosystem | Fast, lightweight, deep Chrome access | Auto-waits, test runner, multi-browser, dev tooling | Fastest to build, resilient to DOM changes |
| Cons | Boilerplate, slow, weak with SPAs | No WebKit, JS/TS-only | Patched browsers, younger ecosystem | Non-deterministic, LLM cost, harder to debug |



