## Why Dark Mode Screenshots? Dark mode has gone mainstream. Most popular websites and apps now support it, and many users prefer it. If you're capturing screenshots for documentation, marketing materials, or visual testing, you need to capture both light and dark mode variants. The challenge? Programmatically telling a website to render in dark mode isn't as simple as toggling a switch. ## How Dark Mode Works on the Web Websites implement dark mode using the CSS `prefers-color-scheme` media query: ```css /* Light mode (default) */ body { background: white; color: #333; } /* Dark mode */ @media (prefers-color-scheme: dark) { body { background: #1a1a1a; color: #e0e0e0; } } ``` The browser tells the website which color scheme the user prefers. To capture dark mode screenshots, we need to tell the browser to report `prefers-color-scheme: dark`. ## Method 1: ToolCenter with Color Scheme Override The simplest approach — use the ToolCenter Screenshot API with the `colorScheme` parameter: ```javascript const axios = require('axios'); async function darkModeScreenshot(url) { const response = await axios.post( 'https://api.toolcenter.dev/v1/screenshot', { url: url, width: 1280, height: 800, format: 'png', colorScheme: 'dark' }, { headers: { 'Authorization': 'Bearer YOUR_API_KEY' }, responseType: 'arraybuffer' } ); return response.data; } ``` ### Python Version ```python import requests def dark_screenshot(url): response = requests.post( 'https://api.toolcenter.dev/v1/screenshot', json={ 'url': url, 'width': 1280, 'height': 800, 'format': 'png', 'colorScheme': 'dark' }, headers={'Authorization': 'Bearer YOUR_API_KEY'} ) return response.content ``` One parameter. That's it. ## Method 2: CSS Injection for Custom Dark Themes Some sites don't use `prefers-color-scheme` — they use a toggle button that sets a class or data attribute. For these, inject CSS: ```javascript async function forceDarkMode(url) { const response = await axios.post( 'https://api.toolcenter.dev/v1/screenshot', { url: url, width: 1280, height: 800, format: 'png', css: ` html { filter: invert(1) hue-rotate(180deg); } img, video, svg { filter: invert(1) hue-rotate(180deg); } ` }, { headers: { 'Authorization': 'Bearer YOUR_API_KEY' }, responseType: 'arraybuffer' } ); return response.data; } ``` The `invert(1) hue-rotate(180deg)` trick inverts all colors and then corrects the hue shift, creating a "fake" dark mode. The second rule re-inverts images and videos so they look normal. ### Pros and Cons of CSS Inversion **Pros:** Works on any website, no dark mode support needed. **Cons:** Colors won't match the site's actual dark theme. Some elements may look odd. ## Method 3: Capturing Both Modes Side by Side For visual testing or comparison materials, capture both versions: ```javascript async function captureBothModes(url) { const [light, dark] = await Promise.all([ axios.post( 'https://api.toolcenter.dev/v1/screenshot', { url, width: 1280, height: 800, format: 'png', colorScheme: 'light' }, { headers: { 'Authorization': 'Bearer YOUR_API_KEY' }, responseType: 'arraybuffer' } ), axios.post( 'https://api.toolcenter.dev/v1/screenshot', { url, width: 1280, height: 800, format: 'png', colorScheme: 'dark' }, { headers: { 'Authorization': 'Bearer YOUR_API_KEY' }, responseType: 'arraybuffer' } ), ]); return { light: light.data, dark: dark.data, }; } ``` Both requests run in parallel, so you get both screenshots in the time it takes to capture one. ## Method 4: JavaScript Execution for Toggle-Based Dark Mode Some websites use JavaScript toggles (e.g., a button that sets `localStorage` or a cookie): ```javascript async function toggleDarkMode(url) { const response = await axios.post( 'https://api.toolcenter.dev/v1/screenshot', { url: url, width: 1280, height: 800, format: 'png', javascript: ` // Common dark mode toggle patterns document.documentElement.setAttribute('data-theme', 'dark'); document.documentElement.classList.add('dark'); localStorage.setItem('theme', 'dark'); `, delay: 1000 // Wait for theme transition }, { headers: { 'Authorization': 'Bearer YOUR_API_KEY' }, responseType: 'arraybuffer' } ); return response.data; } ``` ## Practical Use Cases ### 1. Documentation Screenshots Generate docs screenshots in both modes for your users: ```python import requests import os PAGES = [ 'https://docs.example.com/getting-started', 'https://docs.example.com/api-reference', 'https://docs.example.com/tutorials', ] for page in PAGES: for mode in ['light', 'dark']: response = requests.post( 'https://api.toolcenter.dev/v1/screenshot', json={ 'url': page, 'width': 1280, 'height': 800, 'format': 'png', 'colorScheme': mode, }, headers={'Authorization': 'Bearer YOUR_API_KEY'} ) slug = page.split('/')[-1] filename = f'docs/{slug}-{mode}.png' os.makedirs('docs', exist_ok=True) with open(filename, 'wb') as f: f.write(response.content) print(f'Saved: {filename}') ``` ### 2. Visual Regression Testing Compare dark mode renders across deployments: ```javascript async function testDarkMode(stagingUrl, productionUrl) { const [staging, production] = await Promise.all([ captureScreenshot(stagingUrl, 'dark'), captureScreenshot(productionUrl, 'dark'), ]); // Compare images using pixel-diff or similar const diff = await compareImages(staging, production); if (diff.percentage > 0.1) { console.warn(`Dark mode visual regression detected: ${diff.percentage}% difference`); } } ``` ### 3. App Store / Marketing Screenshots Generate promotional screenshots in dark mode for app store listings: ```javascript const marketingPages = [ { url: 'https://app.example.com/dashboard', name: 'dashboard' }, { url: 'https://app.example.com/analytics', name: 'analytics' }, { url: 'https://app.example.com/settings', name: 'settings' }, ]; for (const page of marketingPages) { const screenshot = await axios.post( 'https://api.toolcenter.dev/v1/screenshot', { url: page.url, width: 1280, height: 800, format: 'png', colorScheme: 'dark', deviceScaleFactor: 2, // Retina quality }, { headers: { 'Authorization': 'Bearer YOUR_API_KEY' }, responseType: 'arraybuffer' } ); fs.writeFileSync(`marketing/${page.name}[email protected]`, screenshot.data); } ``` ## Common Issues and Fixes ### Flash of Light Mode Some sites briefly show light mode before switching. Add a delay: ```json { "delay": 500 } ``` ### Images Look Inverted When using CSS injection, re-invert media elements: ```css img, video, canvas, svg, [style*="background-image"] { filter: invert(1) hue-rotate(180deg); } ``` ### Site Doesn't Support Dark Mode Not all sites have dark mode. Use the CSS inversion technique as a fallback, or accept that some screenshots will be light-only. ## Conclusion Dark mode screenshots are essential for thorough documentation, visual testing, and marketing materials. The ToolCenter makes it trivial with the `colorScheme` parameter — no headless browser setup or complex JavaScript required. For sites without native dark mode support, CSS injection provides a reasonable fallback.