Dark Mode Screenshots
Capture dark mode variants of websites using the colorScheme parameter.
Overview
Many websites support dark mode through the prefers-color-scheme CSS media feature. ScreenshotAPI can emulate this preference, allowing you to capture both light and dark variants of any page that supports it.
Basic Usage
Set the colorScheme parameter to "dark" or "light":
# Dark mode
curl "https://screenshotapi.to/api/v1/screenshot?url=https://github.com&colorScheme=dark" \
-H "x-api-key: $SCREENSHOTAPI_KEY" \
--output github-dark.png
# Light mode
curl "https://screenshotapi.to/api/v1/screenshot?url=https://github.com&colorScheme=light" \
-H "x-api-key: $SCREENSHOTAPI_KEY" \
--output github-light.pngasync function captureWithScheme(url: string, scheme: 'light' | 'dark') {
const params = new URLSearchParams({ url, colorScheme: scheme })
const response = await fetch(
`https://screenshotapi.to/api/v1/screenshot?${params}`,
{ headers: { 'x-api-key': process.env.SCREENSHOTAPI_KEY! } }
)
return Buffer.from(await response.arrayBuffer())
}
// Capture both variants
const [lightBuffer, darkBuffer] = await Promise.all([
captureWithScheme('https://github.com', 'light'),
captureWithScheme('https://github.com', 'dark')
])
await fs.promises.writeFile('github-light.png', lightBuffer)
await fs.promises.writeFile('github-dark.png', darkBuffer)import requests
import os
def capture_with_scheme(url: str, scheme: str) -> bytes:
response = requests.get(
"https://screenshotapi.to/api/v1/screenshot",
params={"url": url, "colorScheme": scheme},
headers={"x-api-key": os.environ["SCREENSHOTAPI_KEY"]}
)
response.raise_for_status()
return response.content
# Capture both variants
for scheme in ["light", "dark"]:
content = capture_with_scheme("https://github.com", scheme)
with open(f"github-{scheme}.png", "wb") as f:
f.write(content)How It Works
When colorScheme=dark is set, ScreenshotAPI emulates the prefers-color-scheme: dark CSS media feature in the browser before taking the screenshot. This affects:
- CSS media queries —
@media (prefers-color-scheme: dark) { ... } - CSS
color-scheme— Elements usingcolor-scheme: light dark matchMediaJavaScript API —window.matchMedia('(prefers-color-scheme: dark)')returnstrue
This means any website that implements dark mode through standard CSS or JavaScript mechanisms will render in dark mode.
Capturing Both Variants
A common pattern is to capture both light and dark screenshots for comparison, documentation, or A/B testing:
interface DualScreenshotResult {
light: Buffer
dark: Buffer
url: string
}
async function captureDualMode(url: string): Promise<DualScreenshotResult> {
const [light, dark] = await Promise.all([
captureWithScheme(url, 'light'),
captureWithScheme(url, 'dark')
])
return { light, dark, url }
}
async function captureWithScheme(url: string, scheme: 'light' | 'dark') {
const params = new URLSearchParams({
url,
colorScheme: scheme,
type: 'webp',
quality: '85'
})
const response = await fetch(
`https://screenshotapi.to/api/v1/screenshot?${params}`,
{ headers: { 'x-api-key': process.env.SCREENSHOTAPI_KEY! } }
)
if (!response.ok) throw new Error(`Failed to capture ${scheme} mode`)
return Buffer.from(await response.arrayBuffer())
}
// Capture and save
const result = await captureDualMode('https://tailwindcss.com')
await fs.promises.writeFile('tailwind-light.webp', result.light)
await fs.promises.writeFile('tailwind-dark.webp', result.dark)Capturing both variants costs 2 credits (1 per screenshot). Use Promise.all to capture them in parallel for faster results.
Use Cases
App Store / Marketing Screenshots
Generate both light and dark variants for app store listings or marketing materials:
const pages = [
{ url: 'https://yourapp.com/dashboard', name: 'dashboard' },
{ url: 'https://yourapp.com/settings', name: 'settings' },
{ url: 'https://yourapp.com/analytics', name: 'analytics' }
]
for (const page of pages) {
for (const scheme of ['light', 'dark'] as const) {
const params = new URLSearchParams({
url: page.url,
colorScheme: scheme,
width: '1280',
height: '720',
type: 'png'
})
const response = await fetch(
`https://screenshotapi.to/api/v1/screenshot?${params}`,
{ headers: { 'x-api-key': process.env.SCREENSHOTAPI_KEY! } }
)
const buffer = Buffer.from(await response.arrayBuffer())
await fs.promises.writeFile(`marketing/${page.name}-${scheme}.png`, buffer)
}
}OG Images with Dark Variant
Generate OG images that match the user's system preference:
// app/api/og/route.ts
export async function GET(request: NextRequest) {
const title = request.nextUrl.searchParams.get('title') ?? ''
const dark = request.nextUrl.searchParams.get('dark') === 'true'
const templateUrl = `${APP_URL}/og-template?title=${encodeURIComponent(title)}`
const params = new URLSearchParams({
url: templateUrl,
width: '1200',
height: '630',
colorScheme: dark ? 'dark' : 'light'
})
// ... fetch and return
}Theme Testing in CI
Verify that dark mode renders correctly across your app:
const routes = ['/', '/about', '/pricing', '/blog']
for (const route of routes) {
for (const scheme of ['light', 'dark'] as const) {
const result = await api.capture({
url: `${baseUrl}${route}`,
colorScheme: scheme,
width: 1440,
height: 900
})
await writeFile(`screenshots/${route.replace('/', '_')}-${scheme}.png`, result.buffer)
}
}Troubleshooting
Dark mode not applied
Some sites implement dark mode through JavaScript class toggling (e.g., adding a dark class to the <html> element) rather than CSS media queries. The colorScheme parameter only affects the prefers-color-scheme media feature — it doesn't toggle JavaScript-based theme switches.
Workarounds:
- Check if the site also respects
prefers-color-schemealongside its JS toggle (many do). - If the site only uses JS, you may need to screenshot a URL that forces dark mode (e.g.,
?theme=darkif the site supports it).
Partial dark mode
Some pages may have components that don't respond to prefers-color-scheme (e.g., embedded iframes, third-party widgets). These will remain in their default color scheme.
Delayed theme application
If the site applies dark mode after a brief flash of light mode, add a short delay:
curl "https://screenshotapi.to/api/v1/screenshot?url=https://example.com&colorScheme=dark&delay=500" \
-H "x-api-key: $SCREENSHOTAPI_KEY" \
--output dark.png