Why I Chose Playwright Over Selenium — and Why You Probably Should Too
A beginner's honest take on two popular browser testing tools — what they do, how they're different, and which one makes more sense to start with in 2026 .
Selenium is the tool everyone starts with. But after trying Playwright, I kept asking myself — why wasn't I using this from the beginning?
When I started learning automation testing, the first name that kept coming up was Selenium. Makes sense — it’s been around since 2004, it’s widely used, and there are loads of tutorials for it.
And while it works, I found myself spending a lot of time on setup and debugging rather than actually writing tests. When I switched to Playwright, things felt noticeably smoother. This blog is me trying to explain the difference — in simple terms, for anyone just getting started.
What do these tools actually do?
Both Selenium and Playwright do the same basic job: they control a browser using code.
Instead of a human clicking around a website to check if it works, you write a script that does the clicking for you — automatically, every time. Think of it like a robot that opens your browser, goes to a website, fills in a form, clicks a button, and checks if the right thing happened. That’s automation testing in a nutshell.
Selenium has been doing this since 2004. Playwright was built by Microsoft in 2020. That 16-year gap matters — because Playwright was designed knowing exactly what frustrated Selenium users for years.
A quick note on setup
You’ll often read in old blogs: “Selenium needs you to download a separate driver file that matches your Chrome version.” That used to be true. Since Selenium 4.6, it handles that automatically — just like Playwright does. So both tools are equally easy to install today:
# Install Selenium
npm install selenium-webdriver
# Install Playwright (also sets up test runner)
npm init playwright@latest
Setup is no longer where they differ. The real differences show up after you start writing tests.
The biggest difference: auto-waiting
Modern websites don’t load everything at once. A button might appear 2 seconds after the page loads. A message might pop up only after an API call finishes.
When Selenium tries to click something that isn’t ready yet — it just fails. The fix is to add “wait” code manually before every action. Here’s the same login test in both tools:
selenium-login.js
// selenium-login.spec.js
const { Builder, Browser, By, until } = require('selenium-webdriver');
const assert = require('assert');
describe('Login page', function () {
let driver;
before(async function () {
// Browser.CHROME enum — Selenium Manager handles the driver automatically
driver = await new Builder().forBrowser(Browser.CHROME).build();
});
it('should fill email and click submit', async function () {
await driver.get('https://myapp.com/login');
// Must wait for each element to be visible before you can interact with it
const emailField = await driver.wait(
until.elementIsVisible(await driver.findElement(By.id('email'))),
5000
);
await emailField.sendKeys('user@test.com');
const submitBtn = await driver.wait(
until.elementIsVisible(await driver.findElement(By.id('submit'))),
5000
);
await submitBtn.click();
});
after(async () => await driver.quit());
});
playwright-login.js
// playwright-login.spec.js
// Run with: npx playwright test
import { test, expect } from '@playwright/test';
test('should fill email and click submit', async ({ page }) => {
await page.goto('https://myapp.com/login');
// No wait code needed — locator() auto-waits before every action
await page.getByLabel('Email').fill('user@test.com');
await page.getByRole('button', { name: 'Submit' }).click();
// Assert the result
await expect(page).toHaveURL(/dashboard/);
});
Same outcome. But the Playwright version is shorter, cleaner, and far less likely to fail randomly. When you’re just learning, random failures for no obvious reason are really frustrating. Playwright removes most of that.
Note: When you’re learning, random test failures are the worst. You think you wrote something wrong, spend an hour debugging — and it was just a timing issue. Playwright’s automatic waiting removes that entire category of confusion.
What Playwright includes out of the box
Playwright ships as a complete testing platform. Selenium is a library — you have to assemble the rest yourself.
Selenium | Playwright |
✗ No built-in video recording | ✓ Records video of every failed test |
✗ No auto screenshot on failure | ✓ Auto screenshot when a test breaks |
✗ No visual step-through debugger | ✓ Trace Viewer — step through failures visually |
✗ No built-in HTML test report | ✓ HTML report, open in browser after any run |
✗ Selenium IDE exists as a separate browser extension | ✓ Codegen built in — click around, get test code |
Try this now: run npx playwright codegen https://google.com in your terminal. A browser opens — you click around, and Playwright writes the test code live on the right side. Zero prior knowledge needed.
More things Playwright can do that surprised me
I thought Playwright was just a “browser clicker.” Turns out it goes further than that:
• API testing. Playwright can test your backend directly — checking that an API endpoint returns the right response. No need to switch to a separate tool like Postman.
• Mobile emulation. Playwright has real device profiles built in — one line of code switches your test to an iPhone or Android screen with the right touch behaviour.
• Network simulation. Simulate a slow or offline connection inside a test. Useful for checking how your app behaves when someone has bad signal.
• Three browser engines. Chromium (Chrome), Firefox, and WebKit (Safari) — all supported, no extra setup. Run the same test across all three from a single command.
Here’s what the API test and mobile emulation look like in code:
api-test.js
const { request } = require('playwright');
const context = await request.newContext();
const response = await context.get('https://myapp.com/api/users');
console.log(response.status()); // 200 means it worked
mobile-test.js
const { chromium, devices } = require('playwright');
const iPhone = devices['iPhone 13']; // built-in device profile
const browser = await chromium.launch();
const page = await browser.newPage({ ...iPhone });
await page.goto('https://myapp.com');
// Now testing as if on a real iPhone 13
Playwright and AI — this is where it really pulls ahead
Here’s something beginners don’t hear enough about: Playwright works really well with AI tools. Selenium, because of its older design, struggles to keep up here.
• MCP — AI controls your browser directly. Playwright has an official plugin called @playwright/mcp. Connect it to an AI assistant like Claude, and the AI can open a real browser, navigate your site, click things, fill forms, and check results — all through a conversation.
• AI writes Playwright code better. When you ask AI tools like GitHub Copilot or Claude to write a test, they produce much cleaner Playwright code than Selenium code. Playwright’s API is modern and consistent — AI tools understand it well.
• Playwright has a built-in agent system — Planner, Generator, and Healer Behind every Playwright MCP run, three agents work together: the Planner reads your instructions and decides what to do, the Generator carries out those steps in a real browser, and the Healer automatically fixes broken steps when a button moves or an ID changes — so your automation keeps working even when the page doesn't. For beginners, this means you spend less time debugging why a test broke and more time actually learning how testing works.
• Write tests in plain English with ZeroStep. ZeroStep is a library that plugs into Playwright and lets you describe test steps in plain English. Here’s how it looks:
login.spec.js
import { test } from '@playwright/test'
import { ai } from '@zerostep/playwright'
test('login test', async ({ page }) => {
await page.goto('https://myapp.com')
// Plain English — no selectors, no IDs needed
await ai('Type user@test.com in the email field', { page, test })
await ai('Click the login button', { page, test })
await ai('Verify the dashboard is visible', { page, test })
})
The ai() function takes your plain English instruction as the first argument, and { page, test } as the second. The AI figures out which element on the page matches your description — no IDs, no CSS selectors needed. Nothing like this exists for Selenium.
• Self-healing selectors — tests that fix themselves. You write a test that clicks #submit-btn. A developer renames it to #confirm-btn. Your test breaks — even though the button is still there. AI tools like Healenium work with Playwright to catch this: they scan the page, find the closest matching element, and update the selector automatically. Playwright’s modern structure makes this kind of AI repair possible. Selenium’s older setup makes it much harder to do.
• Migrate old Selenium tests with AI. If a team already has Selenium tests, they can paste them into any AI assistant and ask it to convert them to Playwright. What used to take days of developer work now takes minutes. The “but we already use Selenium” argument basically disappears.
Is there any reason to still use Selenium?
Honestly, for someone starting fresh in 2026, not many. The one real case where Selenium still wins is testing native mobile apps — actual Android or iOS applications, not just a mobile website. Selenium connects to a tool called Appium for that, and Playwright doesn’t support native mobile apps.
For everything else — web testing, API testing, cross-browser, CI pipelines, AI workflows — Playwright handles it better.
The bottom line
If you’re starting fresh, start with Playwright. The auto-waiting alone saves hours of confusion. The built-in tools (video, reports, Codegen) mean you spend time writing tests, not assembling tools. And the AI support — from MCP to ZeroStep to self-healing selectors — puts it in a different league compared to where Selenium is headed.
Run npm init playwright@latest and then try npx playwright codegen your-site.com. You’ll understand in 10 minutes why most people don’t go back.


