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:
/* 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:
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
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:
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:
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):
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:
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:
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:
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:
{ "delay": 500 }
Images Look Inverted
When using CSS injection, re-invert media elements:
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.