How to Capture Website Screenshots in Dark Mode with ScreenshotAPI
Use ScreenshotAPI’s dark_mode=true option to capture a site’s dark theme. Learn what it can and cannot change, how to add CSS, and how to automate captures.
To request a dark-mode screenshot with ScreenshotAPI, send dark_mode=true to its screenshot endpoint. The option asks the renderer to use the target site’s dark appearance; it does not automatically convert every light page into a well-designed dark theme. The site must support dark mode or include styles that respond to it. ScreenshotAPI documents the option as false by default. See its emulation documentation.
The request endpoint documented by ScreenshotAPI is https://shot.screenshotapi.net/v3/screenshot. Include your account token, the full target URL, and the dark-mode option. The examples below show the request shape; they are not claims of a live capture.
1. Make a dark-mode request
Get an API token from your ScreenshotAPI account dashboard. Then set it in an environment variable so it is not copied into source code or committed to version control. URL-encode the target URL when building a query string; the HTTP libraries below do this for you.
cURL
export SCREENSHOTAPI_TOKEN='YOUR_TOKEN'
curl -G 'https://shot.screenshotapi.net/v3/screenshot' \
--data-urlencode "token=$SCREENSHOTAPI_TOKEN" \
--data-urlencode 'url=https://example.com' \
--data-urlencode 'dark_mode=true' \
--output screenshot.png
Change https://example.com to the page you want. The output filename does not select the response format; use the API’s documented format option if you need a particular image or document type. Check the render reference for the currently documented request parameters.
Python
import os
import requests
TOKEN = os.environ['SCREENSHOTAPI_TOKEN']
response = requests.get(
'https://shot.screenshotapi.net/v3/screenshot',
params={
'token': TOKEN,
'url': 'https://example.com',
'dark_mode': 'true',
},
timeout=90,
)
response.raise_for_status()
with open('screenshot.png', 'wb') as image_file:
image_file.write(response.content)
Install the dependency with python -m pip install requests. The timeout is a client-side limit for waiting on the HTTP response, not a guarantee about how long a render takes.
Node.js
const token = process.env.SCREENSHOTAPI_TOKEN;
if (!token) throw new Error('Set SCREENSHOTAPI_TOKEN first');
const query = new URLSearchParams({
token,
url: 'https://example.com',
dark_mode: 'true',
});
const response = await fetch(
`https://shot.screenshotapi.net/v3/screenshot?${query}`
);
if (!response.ok) {
throw new Error(`ScreenshotAPI returned HTTP ${response.status}`);
}
const image = Buffer.from(await response.arrayBuffer());
await import('node:fs/promises').then(({ writeFile }) =>
writeFile('screenshot.png', image)
);
This uses Node.js’s built-in fetch and URLSearchParams. If the API returns an error response, inspect its status and response body rather than saving that body with an image extension.
2. Understand what dark mode changes
The dark_mode setting is a rendering preference, not a universal color-inversion filter. ScreenshotAPI says dark rendering depends on the target offering a dark theme or having built-in dark-mode styles. Its help page likewise notes that the site must offer a dark-mode interface. A page with no dark styles may therefore remain light or appear only partly changed. Sources: emulation docs and ScreenshotAPI help.
Try the direct option first when you want the same dark appearance a supported site provides to its visitors. If the page needs specific colors or contrast adjustments, use the documented CSS injection feature. Injected CSS is a targeted styling technique: you must decide which page elements and states need changes, and site-specific markup can make a rule unsuitable for another page.
3. Customize the page with CSS when needed
ScreenshotAPI documents a css parameter for applying CSS before capture, as well as css_url for loading a stylesheet. For a one-off adjustment, try the inline option. This example forces a dark background and light text, but it is intentionally minimal: real sites often need additional rules for navigation, links, borders, images, code blocks, and dialogs.
curl -G 'https://shot.screenshotapi.net/v3/screenshot' \
--data-urlencode "token=$SCREENSHOTAPI_TOKEN" \
--data-urlencode 'url=https://example.com' \
--data-urlencode 'dark_mode=true' \
--data-urlencode 'css=html, body { background: #111 !important; color: #eee !important; }' \
--output screenshot.png
Use URL encoding for CSS because characters such as spaces, braces, commas, and # have special meaning in URLs. curl --data-urlencode handles that encoding. In Python or Node.js, pass the CSS as a parameter to the URL-building library rather than concatenating it into the URL yourself.
For repeatable styling across requests, keep the CSS in a stylesheet and pass its URL using css_url, as described in the CSS and JavaScript injection documentation. Use a stylesheet URL that the renderer can access. Keep rules scoped to the intended page when possible, and review captures after site redesigns: selectors and color assumptions can become stale.
4. Verify the result and refine it
- Capture a page that you know has a dark theme and request
dark_mode=true. - Open the returned file and check the actual content, not just whether the request completed.
- Look for mixed light and dark regions, low-contrast text, invisible icons, unstyled form controls, and overlays that remain visible.
- If the site supports dark mode but the appearance is unexpected, check whether the URL opens the correct page state and whether the site requires interaction or a preference to be set.
- If the target has no usable dark styles, add narrowly scoped CSS or accept that an arbitrary page cannot be made consistently dark by the option alone.
For a site you control, validate its own dark-theme behavior in a regular browser as well as in the capture. This helps distinguish a page-theme issue from a request-parameter or capture issue.
5. Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| The screenshot is still light | The page does not provide dark styles, or its theme is controlled by page state that was not set. | Confirm the site supports dark mode. If it does, check its documented theme behavior; otherwise apply page-specific CSS with css or css_url. |
| Only some parts are dark | The page has mixed theme rules, embedded content, or components with their own colors. | Inspect the affected areas and add scoped CSS for those components. Avoid broad rules that make images, logos, or status colors unreadable. |
| The API says the URL is missing or invalid | The parameter may be missing or misnamed, or the target URL may not be in the required form. | Use the exact url parameter and provide a complete URL beginning with https://. The help page describes url_required errors and this URL requirement. |
| The response saved as an image will not open | The response may be an API error body rather than an image. | Check the HTTP status and response body before writing it as an image. In Python call raise_for_status(); in Node.js check response.ok. |
| CSS appears ignored or malformed | Special characters may have been encoded incorrectly, or the selectors do not match the target page. | Pass CSS through a query-parameter encoder or use cURL’s --data-urlencode. Verify the selectors against the page and keep rules specific. |
| A page looks incomplete | The page may depend on scripts, delayed content, or a specific state before capture. | Review the render reference for available capture controls and make sure the page can be reached in the intended state. Do not assume dark mode itself waits for every site-specific interaction. |
The API’s help page also documents common request errors such as url_required and quota-related screenshot_limit_reached. Consult the official help page for its current guidance rather than treating every failed response as a theme problem.
6. Performance, reliability, and cost considerations
- Rendering work: Dark mode may rely on the target’s normal page styles and scripts. CSS injection adds styling work but does not guarantee that a complex page will be visually coherent.
- Repeatability: Prefer a stable target URL and a maintained stylesheet for repeated captures. Revisit selectors and results when the target site changes.
- Error handling: Treat the response as untrusted until its HTTP status is successful. Log the target URL and error details safely, but do not log API tokens.
- Cost and limits: The supplied research does not establish ScreenshotAPI’s current prices or plan limits. Check your account and official product documentation for current quota and billing details before scheduling recurring captures.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server for developers. Its dark mode option can request a dark appearance; as with any theme request, the page’s own support affects the result. A single GET request returns a screenshot or PDF. 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://stripe.com \
-o shot.webp
import requests
r = requests.get(
'https://api.screenshotneo.com/v1/shot',
params={
'access_key': 'YOUR_API_KEY',
'url': 'https://stripe.com',
},
timeout=90,
)
open('shot.webp', 'wb').write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://stripe.com',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo removes cookie banners, popups, and chat widgets before capture; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The Free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000.
Sign up free for 1,000 screenshots a month, with no card required.
FAQ
Does dark_mode=true turn any website dark?
No. ScreenshotAPI says the target needs a dark theme or built-in dark-mode styles. CSS injection can customize a page, but it requires rules suited to that page.
What is the default value?
The documented default is false, so include dark_mode=true when you want to request dark rendering.
Can I apply the same custom theme to many captures?
Yes. ScreenshotAPI documents css_url for loading an external stylesheet before capture. Keep that stylesheet accessible to the renderer and maintain its selectors as the target changes.


