How to Take a Playwright Screenshot With Reduced Motion Enabled
Emulate prefers-reduced-motion before capture, and learn when to disable animations separately for stable Playwright screenshots.
To take a Playwright screenshot with reduced motion enabled, emulate the prefers-reduced-motion: reduce media preference before calling page.screenshot():
await page.emulateMedia({ reducedMotion: 'reduce' });
await page.screenshot({ path: 'screenshot.png' });
This tells the page that the user prefers reduced motion. It does not, by itself, stop every animation. For a full-page image, add fullPage: true. To have Playwright disable animations during capture as well, use the separate animations: 'disabled' screenshot option. See the Playwright Page API and screenshot options.
1. Capture a screenshot with reduced motion
Here is a complete runnable JavaScript example using Playwright’s library. It starts Chromium, opens a page, sets the media preference, captures a screenshot, and closes the browser:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: true });
try {
const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
await page.goto('https://example.com', { waitUntil: 'load' });
await page.emulateMedia({ reducedMotion: 'reduce' });
await page.screenshot({ path: 'screenshot.png' });
} finally {
await browser.close();
}
})();
Install Playwright and its browser if needed with npm install playwright followed by npx playwright install chromium. Run the script with Node.js. The reducedMotion option accepts 'reduce', 'no-preference', or null. Set it before the screenshot and before any application behavior you need to observe that depends on the media preference.
Viewport, full-page, and element screenshots
- Viewport: omit
fullPage, as in the example. Playwright captures the current viewport. - Full page: pass
fullPage: trueto capture the full scrollable page. - One element: locate the target and call
locator.screenshot(); the page media emulation still applies.
await page.emulateMedia({ reducedMotion: 'reduce' });
await page.screenshot({ path: 'full-page.png', fullPage: true });
await page.locator('main').screenshot({ path: 'main.png' });
2. Understand reduced motion versus disabling animations
These controls solve related but different problems:
| Control | What it does | Use it when |
|---|---|---|
page.emulateMedia({ reducedMotion: 'reduce' }) |
Makes the page see the reduced-motion media preference. CSS and application code decide how to respond. | You want to capture or test the experience intended for users who prefer less motion. |
page.screenshot({ animations: 'disabled' }) |
Disables CSS animations, transitions, and Web Animations for the screenshot capture. | You need a still, repeatable capture and the page continues to move. |
Use both when you need the page to respond to reduced motion and need Playwright to suppress animations during capture:
await page.emulateMedia({ reducedMotion: 'reduce' });
await page.screenshot({
path: 'still-full-page.png',
fullPage: true,
animations: 'disabled'
});
Animation disabling is a capture-time behavior, not a substitute for exercising the site’s reduced-motion implementation. If you are verifying accessibility behavior, capture with the emulated preference and assert or inspect the page’s response. Add animation disabling only if you also need to remove remaining motion for a stable image.
3. Set reduced motion for Playwright Test
For tests that should use reduced motion by default, configure the test fixture in playwright.config.ts:
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
reducedMotion: 'reduce',
},
});
The documented values are 'reduce', 'no-preference', and null. The default is 'no-preference'; null resets emulation to system defaults. You can override the setting for a particular page when a test needs a different preference.
For a visual baseline rather than a standalone image file, use Playwright Test’s screenshot assertion:
import { test, expect } from '@playwright/test';
test('reduced-motion page matches its visual baseline', async ({ page }) => {
await page.goto('https://example.com');
await expect(page).toHaveScreenshot('reduced-motion.png');
});
toHaveScreenshot() waits for two consecutive screenshots to match before comparing the resulting capture with the expectation. This makes it useful for visual regression checks; direct page.screenshot() is the straightforward choice when you just need to save an image. See the Playwright visual comparisons guide.
4. Make captures reliable and repeatable
- Choose the preference for the purpose. Use
reduceto exercise the reduced-motion experience. Useno-preferenceto capture the ordinary motion preference. Usenullin Playwright Test to restore system defaults. - Set it before capture. Emulate the preference before taking the screenshot. If application code reads the preference during initialization, set it before navigating so the page sees it from the start.
- Wait for the page state you need. Navigate to the right URL and wait for the relevant content or state before capturing. A reduced-motion preference does not wait for content to load or for application-specific transitions to finish.
- Disable residual animation only when appropriate. Add
animations: 'disabled'for deterministic still images, while remembering that it changes capture behavior beyond merely emulating a visitor preference. - Keep visual comparison environments consistent. Browser rendering can vary by operating system, browser version, settings, hardware, power source, and headless mode. Generate and compare baselines in the same environment for more reliable results.
Reduced motion does not guarantee identical pixels across machines. Pinning the execution environment and browser version is especially useful for visual regression workflows; investigate rendering differences in the page and environment before changing a baseline.
5. Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| The page still animates after setting reduced motion. | The page may not have styles or application logic that respond to prefers-reduced-motion, or the motion may be controlled another way. |
Check the page’s reduced-motion behavior. If the capture must be still regardless, add animations: 'disabled' or use a purpose-built stylesheet. |
| The screenshot does not show the reduced-motion state. | The preference was applied after the relevant page behavior initialized, or the application does not implement a distinct reduced-motion state. | Set the preference before navigation when initialization timing matters, then verify the page responds to the media feature. |
| The image changes between runs or machines. | Rendering can vary with browser, operating system, settings, hardware, power source, or headless mode; animations or changing content may also affect captures. | Use the same environment for baseline creation and comparison. Disable animations for capture if that matches the test’s purpose. |
| A screenshot file is missing or empty. | The screenshot may have been attempted before navigation or the capture path may not be writable. | Await navigation and screenshot calls, check the path and permissions, and ensure the browser process completes the script. |
reducedMotion is rejected in configuration. |
The value may be misspelled or outside the documented set. | Use exactly 'reduce', 'no-preference', or null in Playwright Test configuration. |
6. Performance, reliability, and cost
Reduced-motion emulation is a browser setting; the main work and runtime cost still come from launching the browser, loading the page, waiting for its content, and rendering the requested viewport or full page. Full-page captures and pages with heavy assets can take longer and use more memory than viewport captures. Reuse a browser across multiple captures in a batch where practical, close pages and browsers when finished, and set navigation or operation timeouts to suit the pages you capture.
For repeatable regression checks, prefer Playwright Test’s screenshot assertion and run comparisons in a consistent environment. For a one-off image, save with page.screenshot(). A self-hosted Playwright workflow uses your own browser execution resources; ScreenshotNeo’s API pricing is listed below for its separate hosted screenshot service.
7. Or skip the browser setup
If you need a website screenshot without installing and running a browser, ScreenshotNeo provides a screenshot API and MCP server for developers. One GET request returns an image or PDF. Use its API documentation for available parameters and formats.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo accepts cookie and consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits cost nothing, and response headers report the page verdict and whether the request was billed. Its MCP server offers take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.
The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots; every feature is available on every plan. Those are hosted screenshot captures, not Playwright execution: use Playwright when your task specifically requires browser automation or testing the site’s reduced-motion implementation.
Sign up for 1,000 free screenshots a month, with no card required.
8. FAQ
What is the exact Playwright setting for prefers-reduced-motion?
Call await page.emulateMedia({ reducedMotion: 'reduce' }).
Does reduced motion automatically disable every animation?
No. The emulated preference lets page CSS and code respond; use the separate screenshot animations: 'disabled' option if you need Playwright to stop animations during capture.
Should I use a screenshot file or toHaveScreenshot()?
Use page.screenshot() to save an image. Use toHaveScreenshot() to compare a visual test against an expected baseline.


