How to Emulate Dark Mode for a Playwright Screenshot
Use Playwright’s color scheme emulation to capture dark mode. Choose page, context, or test configuration, then verify the page’s response.
To make a Playwright screenshot use dark mode, emulate the prefers-color-scheme: dark media feature before capturing the page:
await page.emulateMedia({ colorScheme: 'dark' });
await page.screenshot({ path: 'screenshot.png' });
This sets the color scheme preference exposed to the page. It does not force every website to look dark: the application must include styles or logic that respond to that preference. Playwright supports setting the preference on an existing page, at context or page creation, and in Playwright Test configuration. See the official Page API documentation.
1. Capture one page in dark mode
For an existing page, call page.emulateMedia() after creating the page and before taking the screenshot. Here is a complete runnable example using Playwright’s JavaScript library:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'networkidle' });
await page.emulateMedia({ colorScheme: 'dark' });
const prefersDark = await page.evaluate(() =>
matchMedia('(prefers-color-scheme: dark)').matches
);
if (!prefersDark) {
throw new Error('Dark color scheme was not emulated');
}
await page.screenshot({ path: 'dark-mode.png', fullPage: true });
await browser.close();
})().catch((error) => {
console.error(error);
process.exitCode = 1;
});
Install the package with npm install playwright and install its browser with npx playwright install chromium. If your project already uses Playwright Test, use the test runner examples below instead.
Verify both the preference and the rendered page
The media query check confirms the preference available to page JavaScript. It does not prove that the site has a dark theme or that its screenshot is visually correct. Inspect the captured image or check an application-specific theme marker, background, or CSS property as appropriate.
const state = await page.evaluate(() => ({
darkPreference: matchMedia('(prefers-color-scheme: dark)').matches,
lightPreference: matchMedia('(prefers-color-scheme: light)').matches,
}));
console.log(state);
With dark emulation active, the dark query should match and the light query should not. A site may still render a light design if it ignores the preference, applies a user-selected theme over system settings, or loads theme styles only after application code runs.
2. Set dark mode at page or context creation
If every page in a browser context should start with the same preference, set colorScheme when creating the context. This avoids relying on a later per-page setup call:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const context = await browser.newContext({ colorScheme: 'dark' });
const page = await context.newPage();
await page.goto('https://example.com');
await page.screenshot({ path: 'dark-mode.png', fullPage: true });
await context.close();
await browser.close();
})().catch((error) => {
console.error(error);
process.exitCode = 1;
});
You can also pass colorScheme: 'dark' to browser.newPage() when creating a page directly. Use page emulation when changing an existing page’s preference; use context or page creation options when the preference should be in place from the start.
3. Configure Playwright Test
Set the preference for an entire Playwright Test project in playwright.config.ts:
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
colorScheme: 'dark',
},
});
To apply it only to a particular test file or group, configure that scope with test.use():
import { test, expect } from '@playwright/test';
test.use({ colorScheme: 'dark' });
test('renders the dark theme', async ({ page }) => {
await page.goto('https://example.com');
await expect(page).toHaveScreenshot('dark-mode.png', { fullPage: true });
});
Use project-wide configuration when dark mode is the default for the suite. Use scoped configuration when only certain tests cover the dark theme. For tests that compare light and dark behavior, define separate projects or scopes with the appropriate colorScheme value.
4. Generate code with dark color scheme
Playwright’s code generator can open a page with dark color scheme emulation enabled:
npx playwright codegen --color-scheme=dark https://example.com
This is useful when inspecting or recording interactions in a dark-themed state. It does not replace setting the preference in the configuration or test code that will run your automated captures.
5. Pick the right configuration scope
| Scope | How to set it | Use it when |
|---|---|---|
| One existing page | await page.emulateMedia({ colorScheme: 'dark' }) |
You need to change the preference after page creation. |
| New context | browser.newContext({ colorScheme: 'dark' }) |
Pages in that context should share the preference from the start. |
| New page | browser.newPage({ colorScheme: 'dark' }) |
You create a page directly and want its initial preference set. |
| Playwright Test suite | use: { colorScheme: 'dark' } |
The suite or project should default to dark mode. |
| Selected tests | test.use({ colorScheme: 'dark' }) |
Only a test file or group should use dark mode. |
| Code generation | --color-scheme=dark |
You want to inspect a page or record interactions in a dark state. |
For an existing page, the order is important: configure the preference before screenshot capture. When creating a context or page with the preference already set, it applies from the beginning of that page’s work.
6. Media options and limits
colorScheme controls the prefers-color-scheme media feature. The separate media option to emulateMedia() controls the media type, such as screen or print. Print emulation and dark color scheme emulation solve different problems; setting media: 'print' does not request dark mode.
await page.emulateMedia({
media: 'screen',
colorScheme: 'dark',
});
Use the documented 'dark' or 'light' values for this task. The current API documentation marks 'no-preference' as deprecated; passing null disables color-scheme emulation. If you depend on version-specific behavior, check the API docs and types for the Playwright version installed in your project.
7. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| The screenshot is still light. | The page preference may not have been set before capture, or the site may not respond to prefers-color-scheme. |
Set colorScheme: 'dark' before capture, verify the media query, and inspect the app’s theme logic and rendered styles. |
| The dark query is false. | Emulation was applied to a different page, or the call happened after the screenshot. | Call page.emulateMedia({ colorScheme: 'dark' }) on the page being captured before taking the screenshot. |
| Some components stay light. | Those components may use fixed colors, a separate theme setting, or delayed client-side rendering. | Check the component’s CSS and application state. Wait for the relevant content or theme marker before capturing. |
| Tests vary between runs. | Capture timing, animations, fonts, images, or app data may differ independently of color scheme. | Wait for a stable application condition, use deterministic test data, and keep screenshot settings consistent. |
| The API call or config option is rejected. | The project may use another language binding or an older Playwright version. | Check the installed package and its language-specific API reference; this article’s code uses JavaScript/TypeScript spelling. |
| The screenshot file is missing. | The script may fail before capture or save to a different working directory. | Log navigation and capture errors, use an explicit output path, and confirm the process can write to that directory. |
8. Performance, reliability, and cost
Setting a color scheme is a browser emulation setting; it does not require a second browser or a separate screenshot service. The main reliability concern is whether the application has finished applying its theme before capture. Wait for a meaningful application condition when theme selection or page rendering is asynchronous, and keep viewport, data, and capture timing consistent for visual comparisons.
Playwright is an open-source browser automation framework, so this method has no per-screenshot API charge. Your costs come from the machines and infrastructure used to run the browser and from the time required to maintain the capture workflow. For recurring captures, reuse a browser process where appropriate, create isolated contexts for separate runs, and close contexts and browsers when finished.
9. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. For an API capture, pass the dark color scheme as a request option. See the ScreenshotNeo documentation for the current parameter details and response options.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com \
-d color_scheme=dark \
-o dark-mode.webp
ScreenshotNeo accepts the parameter names used by other screenshot APIs, so check the docs for the exact option spelling if you are adapting an existing request. With ScreenshotNeo, cookie banners, popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed; and an MCP server lets AI agents take screenshots. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month, with no card.
FAQ
Does dark color scheme emulation change the site’s saved theme setting?
No. It emulates a browser media preference. A website may also have its own theme control or saved user setting, which can take precedence.
Can I capture both light and dark screenshots?
Yes. Run the capture with colorScheme: 'light' and again with colorScheme: 'dark', keeping the rest of the page and screenshot settings the same.
Does the dark preference apply to every browser page?
It applies to the page where you set it, or to pages created from a context configured with that preference. Configure each independent context as needed.
Does emulation make a page screenshot visually identical across machines?
No. It sets the color scheme preference. Browser version, fonts, viewport, page data, rendering timing, and application behavior can still affect pixels.


