When a test fails in production or unexpectedly breaks during a refactor, stepping through your Playwright script line by line is often faster than logging and guessing. Debugging with the Playwright Inspector, explained simply, gives you a visual, interactive way to pause execution, inspect the DOM in real time, and validate your selectors without rewriting code. Today we'll walk through the tools and techniques that let you see exactly what your browser is doing at each step.
Understanding the Playwright Inspector
The Playwright Inspector is a built-in debugging interface that appears alongside your browser when you run tests in debug mode. It shows your test code on the left, a live browser preview on the right, and controls in the middle to step forward, step backward, and pause execution. You can inspect elements, check the DOM, and even run locator queries in real time without touching your test file.
The Inspector is available for all Playwright browsers—Chromium, Firefox, and WebKit—and works equally well whether you're debugging a single test or a full suite. It's also language-agnostic; the workflow is the same whether you're writing in TypeScript, Python, or Java.
Running Tests with PWDEBUG=1 or --debug
The easiest way to launch the Inspector is to set the PWDEBUG environment variable before running your tests. Here's how it works in practice:
// tests/checkout.spec.ts
import { test, expect } from '@playwright/test';
test('should complete purchase flow', async ({ page }) => {
await page.goto('https://shop.example.com');
await page.click('[data-testid="add-to-cart"]');
await page.click('[data-testid="checkout-btn"]');
await page.fill('[data-testid="email"]', 'user@example.com');
await page.fill('[data-testid="card-number"]', '4111111111111111');
await page.click('[data-testid="submit-order"]');
await expect(page).toHaveURL('/order-confirmation');
});
Run this test with debug mode enabled:
PWDEBUG=1 npm test -- checkout.spec.ts
On Windows PowerShell:
$env:PWDEBUG=1; npm test -- checkout.spec.ts
Alternatively, use the --debug flag with the Playwright test runner:
npx playwright test --debug checkout.spec.ts
Either command launches the Inspector window alongside your browser. The test pauses at the first line, and you control execution from there. You'll see:
- Your test code highlighted on the left with a blue cursor
- The live browser window in the center or right pane
- Step over, step into, and resume buttons at the top
- A console panel at the bottom to evaluate JavaScript expressions
This setup is invaluable when you're not sure why a selector isn't matching or an action fails silently. You can pause right before the failing line, inspect the DOM, and understand what went wrong.
Pausing Execution with page.pause()
Sometimes you want to pause at a specific point in your test without launching the full Inspector. Use page.pause() to freeze execution and drop into the Inspector at that exact moment. This is useful when you have a long test and only need to debug one section:
test('should filter products and add to cart', async ({ page }) => {
await page.goto('https://shop.example.com');
// Apply filters
await page.click('[data-testid="filter-brand"]');
await page.click('text=Nike');
// Pause here to inspect the filtered results
await page.pause();
// Then continue with the add-to-cart flow
await page.click('[data-testid="product-card"]:first-child');
await page.click('[data-testid="add-to-cart"]');
await expect(page.locator('[data-testid="cart-count"]')).toContainText('1');
});
When this test runs (with or without PWDEBUG=1), execution stops at the page.pause() line. The Inspector opens, and you can now examine the DOM, run queries, and verify that your filters worked as expected. Once you've confirmed everything, click the resume button to continue.
page.pause() is also useful in production debugging scenarios. If a test passes locally but fails in CI, you can add a pause, re-run it locally with the same environment variables, and inspect the exact state before the failure.
Exploring Locators Live in the Inspector
One of the most powerful features of the Inspector is the ability to test and refine locators in real time. When execution pauses, the Inspector's console lets you query the DOM directly and see results instantly. This saves enormous amounts of time compared to the old approach of changing your code, rerunning the test, and waiting for it to reach that point again.
For example, suppose you're trying to select a product by its name, but your first attempt isn't working:
test('find product by exact name', async ({ page }) => {
await page.goto('https://shop.example.com');
await page.click('[data-testid="search"]');
await page.fill('[data-testid="search"]', 'Ultraboost 23');
await page.pause(); // Pause after search results load
});
When paused, open the Inspector's console and try different locators without editing your test:
// In the Inspector console:
page.locator('text=Ultraboost 23')
page.locator('[role="link"]:has-text("Ultraboost 23")')
page.locator('a >> text=Ultraboost')
page.locator('a').filter({ hasText: 'Ultraboost 23' })
The Inspector shows you instantly which locator matches elements in the DOM. Once you find one that works, copy it into your test. This interactive approach is much faster than the trial-and-error loop of editing, saving, and rerunning.
You can also inspect the selected elements directly. The Inspector highlights matching nodes in the browser's DOM tree and shows you their HTML. If a locator matches multiple elements when you expected one, you'll see that immediately and can refine your selector.
Using Headed Mode for Visual Checks
Debugging is easier when you can actually see what's happening. By default, Playwright runs in headless mode—no visible browser window. When debugging, switch to headed mode so you can watch the browser's behavior in real time:
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
use: {
// Headed mode enabled for debugging
headless: false,
},
});
Then run your test with the Inspector:
PWDEBUG=1 npx playwright test --headed checkout.spec.ts
Now you'll see the actual browser window alongside the Inspector. You can watch your script click buttons, fill fields, and navigate pages in real time. If a click doesn't work, you'll see the cursor miss its target. If a selector is too broad, you'll see it click the wrong element. Headed mode + Inspector is the gold standard for debugging visual or interaction issues.
You can also pause mid-step and manually interact with the browser—click something yourself, type in a field, or scroll to see if the page behaves differently. Then resume the test to see if your manual input changes the test's behavior.
Common Mistakes
Forgetting to remove page.pause() calls before committing. It's easy to add a pause while debugging and forget to delete it. Your test will hang in CI waiting for manual input that never comes. Always search for and remove page.pause() before pushing code.
Not realizing the Inspector pauses before the line executes. The blue cursor sits on the line about to run, not the one just completed. If you step over a line that fails, the error happens in that step, not the previous one. This confusion can send you debugging the wrong section of code.
Treating Inspector locator queries as production-ready without running the full test. Just because a locator works in the Inspector console doesn't mean it will work when the page is in a different state (after animations, async data load, etc.). Always add the locator to your test and run the full flow to confirm.
Debugging in headless mode without the Inspector. Headless mode + Inspector together are powerful, but headless mode alone with only console logs is slow and error-prone. Always pair debugging with the Inspector or headed mode.
Key Takeaways
- Launch the Inspector with
PWDEBUG=1or--debugto step through tests line by line and see your browser in real time. - Use
page.pause()to drop into the Inspector at a specific point in your test without modifying your configuration. - Test and refine locators in the Inspector's console before adding them to your test code, saving time on edit-run-debug loops.
- Enable headed mode when debugging visual or interaction issues so you can watch the browser behave exactly as your test does.
- The Inspector is fastest when combined with headed mode; use both together for the clearest view of what your test is doing and why it's failing.






Comments
Loading comments…