Of all the Playwright 1.59 additions, --debug=cli is the one nobody's writing about. The official notes mention it once, in the context of agent workflows: "coding agents can now run npx playwright test --debug=cli to attach and debug tests over playwright-cli." Most QA engineers skipped it because they don't have an AI agent driving their tests.
That's a missed opportunity. The CLI debugger is also the cleanest way to debug a failing test from a terminal — useful when you're SSH'd into a CI machine, when you're remote-pairing, or when you just don't want to launch the GUI Inspector for the third time today. After two weeks of using it on real projects, here's what it actually does and when I reach for it.
Table of Contents
- What --debug=cli actually does
- When to reach for the CLI debugger over the GUI Inspector
- The commands that matter
- Scripted debugging: the pattern AI agents use
- Debugging a failed CI run remotely
- Difference vs PWDEBUG=1
- FAQs
What --debug=cli Actually Does
You start a test with the flag:
npx playwright test tests/checkout.spec.ts --debug=cli
The test runs to its first action and pauses, dropping you into an interactive prompt:
[playwright-cli] Paused at tests/checkout.spec.ts:8
await page.goto('/checkout');
>
From the prompt you can step through the test, inspect locators, run arbitrary expressions in the page context, and see logs as they happen. No browser GUI needed.
Compare that to the GUI Inspector (--debug alone), which opens a window that hovers over your code editor. The Inspector is great for visual debugging. The CLI debugger is great for everything else.
When to Reach for the CLI Debugger Over the GUI Inspector
Three cases I now reach for CLI:
1. Tests on a remote machine
You SSH into a CI runner that just failed a test. The runner doesn't have a display. The Inspector won't help. --debug=cli works perfectly over SSH.
2. When you don't want to leave the terminal
If you're already in tmux/Vim/Emacs flow, alt-tabbing to the Inspector breaks concentration. The CLI debugger keeps you in the terminal.
3. Scripted debugging sessions
The CLI debugger is, well, a CLI. You can pipe commands to it, save sessions, replay them. The Inspector is a GUI; you can't automate its workflow.
The Commands That Matter
The most-used commands in the prompt:
| Command | What it does |
|---|---|
n or next | Step over the next action |
c or continue | Continue until next pause/breakpoint/end |
page.url() | Run a Playwright expression in the test context |
locator.count() | Run any locator method inline |
locate <text> | Search the page for elements containing text |
screenshot | Save a PNG of current state |
trace | Dump the current trace to disk |
vars | List variables in current scope |
q or quit | Exit and end the test |
Sample session:
[playwright-cli] Paused at tests/checkout.spec.ts:14
await page.getByRole('button', { name: 'Pay' }).click();
> locate Pay
Found 2 elements:
1. button[role="button"][aria-label="Pay"] @ /checkout
2. div.help-text:has-text("Pay safely with...") @ /checkout
> page.getByRole('button', { name: 'Pay' }).count()
1
> n
[playwright-cli] Stepped to tests/checkout.spec.ts:15
await expect(page).toHaveURL(/\/thank-you/);
> page.url()
'http://localhost:3000/checkout?error=card_declined'
> q
That session just diagnosed the bug: the Pay button click submitted, but the response was a decline, not a success. The redirect didn't fire. Took 30 seconds in the CLI debugger versus 5 minutes in the trace viewer.
Scripted Debugging: The Pattern AI Agents Use
The reason 1.59 shipped this is that AI agents need a way to debug failing tests programmatically. The healer agent (see my agents post) attaches via the CLI debugger, runs commands, reads outputs, and decides what to patch.
You can use the same pattern manually. Save a debug script:
# debug-checkout.txt
locate Pay
page.getByRole('button', { name: 'Pay' }).count()
n
page.url()
screenshot
q
Pipe it in:
npx playwright test tests/checkout.spec.ts --debug=cli < debug-checkout.txt
The session runs non-interactively, dumps the output, exits. Useful for: "every time this test fails, run this diagnostic script" — wire it into your CI's failure-handling step.
Debugging a Failed CI Run Remotely
This is the workflow I use most. A test fails in GitHub Actions. The trace viewer is helpful but I want to actually run a few commands against the failing state.
Steps:
- SSH into the runner (Actions has
action-tmatefor this). - Navigate to the failed test directory.
- Re-run with
--debug=cli. - Step through to the failure point.
- Inspect locators, page state, network state.
- Hypothesize the cause, test the hypothesis with another command.
- Exit, fix the bug, push.
Total time on the runner: usually under 10 minutes. With the GUI Inspector this workflow is impossible without forwarding X11 (don't bother).
Difference vs PWDEBUG=1
PWDEBUG=1 opens the GUI Inspector. --debug=cli opens the terminal debugger. They're alternative entry points to the same underlying debugging system; pick based on environment:
- Local dev with GUI:
PWDEBUG=1 - SSH/CI/headless:
--debug=cli - Scripted/automated:
--debug=cliwith input redirection
You can use both in the same project. They're not mutually exclusive.
FAQs
Does this work in headed and headless modes?
Both. The CLI debugger doesn't care about browser visibility — it pauses execution and lets you inspect either way.
Can I set breakpoints at specific lines?
Yes — await page.pause() in your test code creates a breakpoint that the CLI debugger respects (just like the GUI Inspector).
Does it work with multiple workers?
Run with --workers=1 when debugging. Multiple workers + interactive debugger don't compose.
Can I see network activity?
Yes — page.requests() shows the request log up to the current point. page.responses() shows responses.
What about console logs from the page?
Type console in the prompt to see captured console messages from the page.
Can I evaluate JavaScript in the page?
page.evaluate(() => window.someGlobal) works — same syntax as in test code, evaluated against the live page.
Does it integrate with the trace viewer?
Yes — trace command saves the current state to a trace file you can open in the viewer. Useful for sharing the state with a teammate.
What about IDE integration?
VS Code's Playwright extension has its own debug protocol that works with breakpoints in the editor. The CLI debugger is for terminal-first workflows; IDE users will mostly use the extension.
Can I use this in CI to gather diagnostic info on every failure?
Yes. Write a debug script that captures the diagnostic info you care about, run it conditionally on test failure, attach the output to your CI artifacts. Cleaner than just trace files because you can include any expression you want.
Will the CLI debugger be deprecated when the agents mature?
Unlikely. The agents use it as their backbone. As long as agents are part of Playwright, the CLI debugger stays.
Wrap-Up
The CLI debugger is one of those features that quietly changes your workflow if you let it. It's not a replacement for the trace viewer or the GUI Inspector — it's a third option that fits the gap they don't cover. For terminal-first debugging, remote CI sessions, and scripted diagnostics, it's now my default.
If your team is exploring 1.59's features and wants help wiring them into your debug workflow, that's part of what I cover in framework engagements. Or book a free call.
Related reading:
Tayyab Akmal
AI & QA Automation Engineer
6 years of catching critical bugs in fintech, e-commerce, and SaaS — then building the Playwright and Selenium automation that prevents them from shipping again.