Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan Now×
Skip to content
World desk5 min

How to Test a Website’s Dark Mode with Puppeteer Screenshots

Emulate prefers-color-scheme in Puppeteer, verify the page sees it, and compare light and dark screenshots under consistent conditions.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To test dark mode with Puppeteer, emulate the prefers-color-scheme: dark media feature before taking a screenshot, verify that the page sees the preference, and compare the rendered image with a light-mode capture under the same conditions. The media-query check confirms the browser preference reached the page; it does not prove that every component is styled correctly.

Set the color scheme before capturing

Puppeteer exposes the browser’s preferred color scheme to the page through page.emulateMediaFeatures(). Set it before capturing the page so CSS using @media (prefers-color-scheme: dark) can respond.

As an Amazon Associate I earn from qualifying purchases.

The examples below use the Puppeteer 25.12.0 API documented at the time of writing. The emulation guide is published under the /next/ documentation path, so check the documentation matching the Puppeteer version installed in your project before relying on an API signature. See the Puppeteer media emulation API.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Runnable example: capture dark and light

Install Puppeteer in a Node.js project with npm install puppeteer, then save this script as dark-mode-test.js. Replace the example URL with the page you want to test.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: true });

  try {
    const page = await browser.newPage({
      viewport: { width: 1440, height: 900 },
      deviceScaleFactor: 1,
    });

    await page.goto('https://example.com', { waitUntil: 'networkidle2' });

    for (const scheme of ['light', 'dark']) {
      await page.emulateMediaFeatures([
        { name: 'prefers-color-scheme', value: scheme },
      ]);

      const isDark = await page.evaluate(() =>
        window.matchMedia('(prefers-color-scheme: dark)').matches
      );
      const isLight = await page.evaluate(() =>
        window.matchMedia('(prefers-color-scheme: light)').matches
      );

      console.log(`${scheme}: dark=${isDark}, light=${isLight}`);
      await page.screenshot({ path: `${scheme}.png` });
    }
  } finally {
    await browser.close();
  }
})();

Run it with node dark-mode-test.js. The dark run should report dark=true and light=false; the light run should report dark=false and light=true. Puppeteer’s documented verification method uses window.matchMedia for these checks. The script produces light.png and dark.png in the current directory.

The navigation option waitUntil: 'networkidle2' is a useful example, not a guarantee that a page is visually settled. Replace or supplement it with your application’s own readiness condition when content, fonts, animations, or images continue changing after network activity falls quiet. Puppeteer documents both navigation lifecycle options and Page.screenshot() in its screenshot guide.

Capture a full page or one element

For a full-page image, set fullPage: true in the screenshot options:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
await page.screenshot({ path: `${scheme}-full.png`, fullPage: true });

To isolate a component, find it by selector and take an element screenshot:

const card = await page.$('.product-card');
if (!card) throw new Error('Expected .product-card was not found');
await card.screenshot({ path: `${scheme}-product-card.png` });

Puppeteer documents path and fullPage as screenshot options and provides ElementHandle.screenshot() for element capture. See the Page.screenshot API and ElementHandle.screenshot API.

Make dark-versus-light comparisons fair

A useful comparison changes the scheme and nothing else. Keep these conditions fixed across the two captures:

  • The same URL, query parameters, login state, and test data.
  • The same viewport dimensions and device scale factor.
  • The same browser and Puppeteer versions.
  • The same navigation and application-readiness conditions.
  • The same capture scope, such as viewport, full page, or one component.

Review the images for text and background legibility, including secondary text; links, controls, borders, focus indicators, and disabled states; logos, charts, and images that may need alternate treatments; and browser-provided controls or scrollbars. Also look for theme-specific layout shifts or overlays. These are practical review checks, not a substitute for assertions or for testing the browser and viewport combinations your project supports.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Know what the browser is being asked to do

prefers-color-scheme expresses a preference

The CSS prefers-color-scheme media feature detects whether a user has indicated a preferred color scheme. Its dark value represents a dark preference; light also covers the case where there is no active preference. Emulating the feature tests how the page responds to that preference. It does not force the site to implement a dark theme. See MDN’s prefers-color-scheme reference.

color-scheme affects browser-provided UI too

The CSS color-scheme property tells the user agent which schemes an element supports. That can influence browser-provided surfaces such as form controls, scrollbars, and canvas backgrounds; page components still need appropriate theme-aware styling. See MDN’s color-scheme reference.

A document can also declare supported schemes with <meta name="color-scheme" content="light dark">. MDN recommends placing this declaration in the document head before styles so the user agent can learn the preferred scheme early in rendering. It communicates support and preference order; it does not replace the page’s theme styles. See MDN’s color-scheme meta reference.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

What a screenshot can—and cannot—show

A screenshot records one rendered state for the chosen browser, viewport, page content, and timing. A correct matchMedia result shows that the page can observe the emulated preference, while the image shows what was rendered in that particular run. Neither alone establishes accessibility or compatibility across browsers, devices, and states. For important behavior, pair image review with explicit assertions and test the environments your project supports.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Troubleshoot common failures

  • The media-query check is false in the dark run: Confirm emulateMediaFeatures() ran before the check and uses the exact feature name prefers-color-scheme with value dark. Check your installed Puppeteer version’s matching API documentation if the call fails.
  • The check passes but the page still looks light: The check confirms the emulated preference, not that the site has dark-mode CSS or that all components use it. Inspect the page’s theme rules and any app-level theme setting separately.
  • The screenshot captures incomplete or changing content: A network-idle condition may not match the app’s visual readiness. Wait for a project-specific selector, state, or other readiness signal before capturing.
  • The light and dark images differ for reasons beyond theme: Keep URL, viewport, device scale factor, browser/runtime, data, and readiness conditions identical between runs.
  • An element screenshot fails or misses the expected target: Check that the selector matches an element after the page is ready. The example throws a clear error if .product-card is absent.

Or skip the browser setup

ScreenshotNeo provides a screenshot API and MCP server. Its one-call API can return an image or PDF; the example below requests a WebP screenshot. See the ScreenshotNeo documentation for request options.

curl -G "https://api.screenshotneo.com/v1/shot" 
  -d access_key=YOUR_API_KEY 
  --data-urlencode url=https://example.com 
  -o shot.webp

ScreenshotNeo accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each of those steps can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for AI agents. The free plan includes 1,000 shots a month with no card; paid plans start at $5 for 3,000 shots.

Sign up for ScreenshotNeo’s free plan to try it with 1,000 screenshots a month and no card.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Windows Errors? Fix Them Before They SpreadFree repair scan
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.