Dark Mode Screenshots: How to Capture Websites in Dark Theme
Learn how to capture website screenshots in dark mode using CSS media queries, the prefers-color-scheme override, and the ToolCenter Screenshot API.
By Christian Mesa·Updated Feb 27, 2026
## 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.