When we think about performance testing, we usually picture big tools with big numbers — JMeter, Gatling, Locust, or Google Lighthouse — hammering backend servers with virtual users or analyzing static audit scores. These tools are great, no doubt. But here’s the twist: what if you could assess your app’s performance like a real user would experience it?
That’s where Playwright steps in — and no, it’s not just for end-to-end testing anymore.
Yep, that’s right. You probably already know Playwright as Microsoft’s slick browser automation framework for testing UIs. It runs on Chromium, Firefox, and WebKit — headless or headed — and makes functional testing across browsers a breeze.
But here’s the cool part: Playwright can also act as your window into the front-end performance world. It runs real browsers, executes actual user flows, and lets you measure load times, responsiveness, and resource usage.
Let’s dive into how you can turn Playwright into a lightweight performance lab for your app.
Performance is about how fast and how smooth your app feels — not just how fast your server responds. Playwright helps you capture that “feel,” thanks to a few key superpowers:
Playwright doesn’t fake it. It spins up actual browser instances, loads your site, runs scripts, fetches resources, and interacts with the UI — just like your users do.
That means you can:
Testing Chrome only? That’s not enough. Playwright lets you compare performance across Chromium, Firefox, and WebKit, which can uncover browser-specific slowdowns or rendering issues.
Want to know how your app performs on a 3G connection or a mid-range device? Playwright supports:
This is the secret sauce. You can extend your existing functional tests to include performance metrics — without maintaining a separate test suite or learning a new tool.
Before we get too excited, let’s be clear about what Playwright doesn’t do:
Load testing at scale — It runs one browser per test. You won’t simulate 1,000 users hammering your server.
Backend metrics — No server-side CPU, memory, or DB insights.
Fancy dashboards — You’ll need to roll your own reports or export to external tools.
That said, Playwright isn’t trying to replace JMeter or Lighthouse. It’s a complementary tool — and it shines when used right.
Here’s a quick way to calculate how long your page takes to fully load:
tsCopyEditimport { chromium } from 'playwright';
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
const timing = JSON.parse(await page.evaluate(() => JSON.stringify(window.performance.timing)));
const loadTime = timing.loadEventEnd - timing.navigationStart;
console.log(`Page load time: ${loadTime} ms`);
await browser.close();
})();
Or use the modern PerformanceNavigationTiming
API:
tsCopyEditconst navTiming = await page.evaluate(() => {
const [entry] = performance.getEntriesByType('navigation');
return {
domContentLoaded: entry.domContentLoadedEventEnd,
loadEvent: entry.loadEventEnd,
};
});
Track slow-loading images, scripts, or styles:
tsCopyEditconst resources = await page.evaluate(() =>
performance.getEntriesByType('resource').map(r => ({
name: r.name,
type: r.initiatorType,
duration: r.duration,
size: r.transferSize,
}))
);
console.table(resources);
This helps you pinpoint bloated assets dragging down your UX.
Want to know how fast the UI responds after clicking a button?
tsCopyEditconst start = Date.now();
await page.click('#submitBtn');
await page.waitForSelector('.result');
const duration = Date.now() - start;
console.log(`UI response time: ${duration} ms`);
Great for measuring AJAX requests or SPA transitions.
Throttle the network like it’s 2010:
tsCopyEditconst context = await browser.newContext();
const client = await context.newCDPSession(page);
await client.send('Network.emulateNetworkConditions', {
offline: false,
downloadThroughput: 400 * 1024 / 8,
uploadThroughput: 400 * 1024 / 8,
latency: 400,
});
Slow down the CPU for realism:
tsCopyEditawait client.send('Emulation.setCPUThrottlingRate', { rate: 4 }); // 4x slower
Record visual feedback while testing:
tsCopyEditawait page.screenshot({ path: 'before.png' });
await context.tracing.start({ screenshots: true });
await page.goto('https://example.com');
await context.tracing.stop({ path: 'trace.zip' });
Analyze it with the Playwright Trace Viewer.
Here’s how to bake performance checks into GitHub Actions:
yamlCopyEditjobs:
performance_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm install
- run: node performance-test.js
You can even set thresholds and fail builds if your app starts slowing down.
Playwright isn’t a silver bullet — it won’t replace your backend stress tests or performance dashboards. But it does give you a powerful, flexible way to measure how real users experience your app — and that’s invaluable.
Whether you're a QA engineer looking to level up your tests or a developer who cares about performance as much as features, adding Playwright to your toolkit brings you one step closer to delivering fast, responsive, and delightful user experiences.