Playwright slowMo slows every browser action down by a fixed number of milliseconds so you can watch what a test is doing. Set slowMo: 500 and each click, fill and navigation is followed by a half-second pause. It is great for demos and for seeing a test with your own eyes.
It is also widely misused as a "fix" for flaky tests. It isn't one, and this guide shows why with a test you can run yourself. If your goal is a stable test rather than a slow one, the Playwright wait guide is where you want to be. Below: where to set slowMo in Playwright Test and in a script, headed mode, what slowMo does and doesn't slow down, and better debugging tools. All examples are JavaScript and ran on Playwright 1.62.1.
Quick answer: in playwright.config.js add use: { launchOptions: { slowMo: 500 } }, then run npx playwright test --headed. There is no --slow-mo CLI flag for playwright test.
What Playwright slowMo Does
slowMo is a browser launch option. The type definitions describe it as: "Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going on." It is available on browserType.launch(), launchPersistentContext() and connect().
In the 1.62 source, the pause is added after each operation that is flagged for slow motion: navigation (goto, reload, goBack), and input actions such as click, dblclick, fill, press, check, hover, selectOption, setInputFiles, plus raw mouse and keyboard calls. It is one fixed delay per action, not a smarter wait.
How to Set slowMo in Playwright Test
In the test runner, slowMo goes inside launchOptions. For one spec file, use test.use at the top:
const { test, expect } = require('@playwright/test'); // Slow down every action in this file by 500 ms test.use({ launchOptions: { slowMo: 500 } }); test('add two todos in slow motion', async ({ page }) => { await page.goto('https://demo.playwright.dev/todomvc'); const input = page.getByPlaceholder('What needs to be done?'); await input.fill('Watch Playwright type'); await input.press('Enter'); await input.fill('Then check it off'); await input.press('Enter'); await page.getByRole('checkbox', { name: 'Toggle Todo' }).first().check(); await expect(page.getByTestId('todo-title')).toHaveText([ 'Watch Playwright type', 'Then check it off', ]); await expect(page.getByTestId('todo-count')).toHaveText('1 item left'); });
For the whole project, put it in the config. Hard-coding a delay for everyone is a bad idea, so read it from an environment variable you choose. SLOWMO below is our own variable, not something Playwright reads by itself:
// @ts-check const { defineConfig } = require('@playwright/test'); module.exports = defineConfig({ testDir: './tests', use: { headless: !process.env.SLOWMO, // headed when slowing down launchOptions: { slowMo: Number(process.env.SLOWMO) || 0, // SLOWMO=500 npx playwright test }, }, });
# Normal speed, headless npx playwright test # Headed, 500 ms after every action SLOWMO=500 npx playwright test
On Windows PowerShell, set the variable first: $env:SLOWMO=500; npx playwright test.
slowMo in a Node Script with chromium.launch
Outside the test runner, pass slowMo straight to launch(). Pair it with headless: false or there is nothing to watch:
const { chromium } = require('playwright'); (async () => { const browser = await chromium.launch({ headless: false, slowMo: 250 }); const page = await browser.newPage(); await page.goto('https://the-internet.herokuapp.com/login'); await page.getByLabel('Username').fill('tomsmith'); await page.getByLabel('Password').fill('SuperSecretPassword!'); await page.getByRole('button', { name: 'Login' }).click(); console.log(await page.locator('#flash').innerText()); await browser.close(); })();
You logged into a secure area! ×
This is the classic setup for recording a demo video or showing a stakeholder what an automated flow does.
slowMo + Headed Mode (and the Missing CLI Flag)
slowMo on its own does nothing visible. Playwright Test runs headless by default, so you need one of these:
npx playwright test --headedon the command line, oruse: { headless: false }in the config (the example config above switches automatically whenSLOWMOis set).
People often look for a matching command-line flag. In Playwright 1.62.1 there isn't one. npx playwright test --help lists --headed, --debug and --ui, but nothing for slow motion, and passing one fails straight away:
$ npx playwright test --slow-mo 500 error: unknown option '--slow-mo'
Playwright also doesn't read a built-in slowMo environment variable; it only reads the option you pass in code. That is why the config above reads its own SLOWMO variable. (Python is different: the pytest-playwright plugin has a --slowmo option, covered in the Playwright Python tutorial.)
What slowMo Slows Down (and What It Doesn't)
With slowMo: 1000, every action and navigation gets about one extra second, while assertions and reads are not delayed at all:
| Call | Extra delay with slowMo: 1000 | Slowed? |
|---|---|---|
page.goto() | About 1 s | Yes |
locator.fill() | About 1 s | Yes |
locator.press('Enter') | About 1 s | Yes |
locator.check() | About 1 s | Yes |
locator.hover() | About 1 s | Yes |
expect(...).toHaveText() | None | No |
locator.textContent() | None | No |
page.evaluate() | None | No |
locator.waitFor() | None | No |
Here is the same check as a test that passes, so you can run it yourself:
const { test, expect } = require('@playwright/test'); test.use({ launchOptions: { slowMo: 1000 } }); test('slowMo delays actions, not assertions', async ({ page }) => { await page.goto('https://demo.playwright.dev/todomvc'); const input = page.getByPlaceholder('What needs to be done?'); let start = Date.now(); await input.fill('slow'); // action: delayed const fillMs = Date.now() - start; await input.press('Enter'); start = Date.now(); await expect(page.getByTestId('todo-title')).toHaveText('slow'); // assertion: not delayed const expectMs = Date.now() - start; console.log({ fillMs, expectMs }); expect(fillMs).toBeGreaterThanOrEqual(1000); expect(expectMs).toBeLessThan(1000); });
{ fillMs: 1039, expectMs: 15 }
So slowMo is a pause after actions. Assertions and reads run at full speed. Keep that in mind for the next section.
Does your test pass with slowMo and fail without it? Then the test is missing a wait, and slowMo is covering for it. See which waits cause flaky Playwright tests and how to fix them →
Why slowMo Is Not a Fix for Flaky Tests
A flaky test is usually a race: the test acts or checks before the app is ready. Adding slowMo gives the app an extra half-second after every action, so the race goes away on your laptop. Then CI runs without slowMo (or on a slower machine where 500 ms isn't enough) and the test fails again.
It also costs a lot. The one-test example above has six actions, so SLOWMO=500 adds at least 3 seconds to it. Across a few hundred tests, that is a long CI run that still isn't reliable.
The fix is to wait for the actual condition:
| Symptom | Wrong fix | Right fix |
|---|---|---|
| Clicks a button before it is ready | slowMo or waitForTimeout | Nothing: auto-waiting already waits for visible, enabled and stable. Check the locator. |
| Checks text before the API returns | slowMo | await expect(locator).toHaveText(...), which retries |
| Needs the API response itself | slowMo | waitForResponse, started before the action |
| Next step depends on a redirect | slowMo | waitForURL or expect(page).toHaveURL() |
The flaky tests guide walks through more of these patterns.
Better Tools for Debugging: UI Mode, --debug, Trace Viewer
slowMo shows you the test at a slower speed, but you can't pause it, rewind it or inspect anything. These built-in tools do much more:
- UI Mode (
npx playwright test --ui): run tests, see a timeline, click any action to see the DOM before and after. See the UI Mode tutorial. - Debug mode (
npx playwright test --debug): opens the Playwright Inspector and pauses before each action so you step through at your own speed. The help text describes it as a shortcut forPWDEBUG=1plus--timeout=0 --max-failures=1 --headed --workers=1. More in how to debug Playwright tests. - Trace viewer: record with
--trace on(ortrace: 'on-first-retry'in config) and open the trace after a failure, including failures in CI where you can't watch at all. See the trace viewer tutorial.
Use slowMo when you want to show a test. Use these when you want to understand one. And for the commands to run tests in each mode, see how to run Playwright tests.
Frequently Asked Questions
What is slowMo in Playwright?
slowMo is a browser launch option that adds a fixed pause, in milliseconds, after each Playwright operation such as goto, click, fill or press. It exists so you can see what the test is doing. It does not change what the test waits for.
How do I set slowMo in Playwright Test?
Put it under launchOptions: use: { launchOptions: { slowMo: 500 } } in playwright.config.js, or test.use({ launchOptions: { slowMo: 500 } }) at the top of a single spec file. Add headless: false or run with --headed so you can actually watch.
Is there a --slow-mo flag for npx playwright test?
No. In Playwright 1.62 the test runner has no slowMo flag; npx playwright test --slow-mo 500 fails with "unknown option '--slow-mo'". Read your own environment variable in the config instead, for example slowMo: Number(process.env.SLOWMO) || 0.
Does slowMo slow down expect assertions?
No. With slowMo set to 1000, fill and press each take about 1 second longer, while an expect assertion, textContent, evaluate and locator.waitFor return in a few milliseconds. slowMo applies to actions and navigation, not to assertions or reads.
Can slowMo fix flaky Playwright tests?
No. It adds a fixed delay after each action, which can hide a race condition on your machine and then fail in CI where the timing differs. Fix the wait instead: use web assertions, waitForResponse or waitForURL for the thing the test depends on.
What should I use instead of slowMo to debug?
UI Mode (npx playwright test --ui) to watch and step through tests with a timeline, --debug to step through actions in the Playwright Inspector, and the trace viewer to see DOM snapshots and network calls for each step of a failed run.
Asim Noaman
Senior QA Automation Engineer & AI Testing Specialist
With years of hands-on experience building test automation frameworks for production applications, Asim specializes in combining traditional QA methodologies with cutting-edge AI tools. He has helped teams adopt Playwright and AI-driven testing workflows to ship faster with fewer bugs.
Flaky Tests Start Here
Slowing Tests Down Hides the Bug. Fixing the Wait Removes It.
If a test passes with slowMo and fails without it, the problem is a missing or wrong wait. The page below shows the waits behind most flaky Playwright tests and how the Playwright + Claude AI course teaches you to fix them, in JavaScript.
- Auto-waiting, web assertions and network waits, used correctly
- Debugging with traces, UI Mode and the Inspector
- Claude AI + Playwright MCP Server to find and fix flaky tests
- 4.5★ on Udemy, 510+ students, 30-day money-back guarantee
Ready now? Enroll on Udemy · Know your waits? Take the practice tests