Browser Emulation
The API runs a real Chromium browser to capture screenshots. Browser emulation lets you control how that browser behaves — what it looks like to the website, where it appears to be located, and what preferences it reports. This is useful for capturing dark mode versions, bypassing bot detection, or screenshotting geo-restricted content.
Dark mode
Many websites offer a dark theme that activates based on the user's system preference. The dark_mode parameter tells the browser to report that it prefers dark colors.
| Parameter | Type | Default | Description |
|---|---|---|---|
dark_mode | boolean | false | Emulate prefers-color-scheme: dark. |
This only works for websites that implement dark mode through the CSS prefers-color-scheme media query. Sites that toggle dark mode through JavaScript or cookies may need a different approach — see CSS & JS Injection for setting cookies or injecting theme-switching scripts.
Example: Dark mode screenshot
const response = await fetch('https://api.screenshotrun.com/v1/screenshots', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: 'https://example.com',
dark_mode: true,
format: 'webp',
}),
});
const { data } = await response.json();
console.log(data.links.image);
import requests
response = requests.post(
"https://api.screenshotrun.com/v1/screenshots",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"url": "https://example.com",
"dark_mode": True,
"format": "webp",
},
)
data = response.json()["data"]
print(data["links"]["image"])
$response = Http::withToken('YOUR_API_KEY')
->post('https://api.screenshotrun.com/v1/screenshots', [
'url' => 'https://example.com',
'dark_mode' => true,
'format' => 'webp',
]);
$data = $response->json('data');
curl -X POST https://api.screenshotrun.com/v1/screenshots \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"dark_mode": true,
"format": "webp"
}'
require "net/http"
require "json"
uri = URI("https://api.screenshotrun.com/v1/screenshots")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_KEY"
request["Content-Type"] = "application/json"
request.body = {
url: "https://example.com",
dark_mode: true,
format: "webp",
}.to_json
response = http.request(request)
data = JSON.parse(response.body)["data"]
body, _ := json.Marshal(map[string]any{
"url": "https://example.com",
"dark_mode": true,
"format": "webp",
})
req, _ := http.NewRequest("POST",
"https://api.screenshotrun.com/v1/screenshots",
bytes.NewBuffer(body))
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var result map[string]any
json.NewDecoder(resp.Body).Decode(&result)
fmt.Println(result["data"])
var client = HttpClient.newHttpClient();
var body = """
{
"url": "https://example.com",
"dark_mode": true,
"format": "webp"
}
""";
var request = HttpRequest.newBuilder()
.uri(URI.create("https://api.screenshotrun.com/v1/screenshots"))
.header("Authorization", "Bearer YOUR_API_KEY")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
var response = client.send(
request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Reduced motion
CSS animations can cause screenshots to capture mid-transition — elements half-faded, progress bars mid-fill, carousels between slides. The reduced_motion parameter tells the browser to prefer reduced motion, which disables CSS animations and transitions on sites that respect this preference.
| Parameter | Type | Default | Description |
|---|---|---|---|
reduced_motion | boolean | false | Emulate prefers-reduced-motion: reduce. |
Example: Static screenshot without animations
curl -X POST https://api.screenshotrun.com/v1/screenshots \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"reduced_motion": true
}'
Not all sites respect prefers-reduced-motion. For sites that don't, you can force-disable animations with CSS injection: "css": "*, *::before, *::after { animation: none !important; transition: none !important; }"
Custom User-Agent
Some websites serve different content based on the User-Agent string — a mobile browser gets a different layout, Googlebot gets a different version, and some sites block unrecognized user agents entirely.
| Parameter | Type | Default | Description |
|---|---|---|---|
user_agent | string | — | Custom User-Agent string. Overrides device preset UA. Max 500 characters. |
Example: See the page as Googlebot
curl -X POST https://api.screenshotrun.com/v1/screenshots \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"user_agent": "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
}'
Stealth mode
Some websites detect headless browsers (Puppeteer, Playwright) and block them or show CAPTCHAs. They check for automation signals like the navigator.webdriver flag, missing browser plugins, or inconsistent WebGL vendor strings.
| Parameter | Type | Default | Description |
|---|---|---|---|
stealth | boolean | false | Hide browser automation signals to bypass bot detection. |
Stealth mode patches the browser to look like a regular user's Chrome: it hides the WebDriver flag, reports normal plugin counts, and provides consistent WebGL vendor information. Use it when a site returns blank pages, CAPTCHAs, or "Access Denied" errors.
Example: Capture a bot-protected site
curl -X POST https://api.screenshotrun.com/v1/screenshots \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://protected-site.com",
"stealth": true,
"delay": 2
}'
Timezone
Pages that display times, dates, or schedules use the browser's timezone to format them. By default, the browser uses the server's timezone. The timezone parameter lets you see the page as it would appear for a user in any timezone.
| Parameter | Type | Default | Description |
|---|---|---|---|
timezone | string | — | IANA timezone (e.g. America/New_York, Europe/Berlin, Asia/Tokyo). |
This affects JavaScript's Date object and the Intl formatting API. Dashboards, calendars, event listings, and news feeds will display times in the specified timezone.
Example: Dashboard in Tokyo time
curl -X POST https://api.screenshotrun.com/v1/screenshots \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/dashboard",
"timezone": "Asia/Tokyo"
}'
Geolocation
The geolocation parameter emulates GPS coordinates in the browser. When a page calls navigator.geolocation, it receives the coordinates you specify. This is useful for capturing maps, local search results, and location-aware content.
| Parameter | Type | Description |
|---|---|---|
geolocation | object | Object with latitude (-90 to 90), longitude (-180 to 180), and optional accuracy in meters. Business plan only. |
The geolocation parameter only affects what the browser reports via the JavaScript Geolocation API. It does not change the IP address of the request — the website will still see the server's IP address. For sites that use IP-based geo-detection (most do), combine geolocation with a proxy in the target region for full geo-spoofing.
Example: Google Maps centered on Paris
curl -X POST https://api.screenshotrun.com/v1/screenshots \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://maps.google.com",
"geolocation": {
"latitude": 48.8566,
"longitude": 2.3522,
"accuracy": 100
}
}'
Proxy
The proxy parameter routes all browser traffic through a proxy server you provide. The website sees the proxy's IP address instead of the API server's IP. This is essential for capturing geo-restricted content, bypassing IP-based blocks, or seeing regional pricing pages.
| Parameter | Type | Description |
|---|---|---|
proxy | string | HTTP or SOCKS5 proxy URL. Format: http://user:pass@host:port. Business plan only. Max 2,048 characters. |
ScreenshotRun does not provide built-in proxies. You need a proxy from an external provider such as Bright Data, Decodo, or Geonode. Both HTTP and SOCKS5 proxies are supported.
Each proxy request launches a dedicated browser instance — no sessions are shared between requests.
Example: Capture through a proxy
curl -X POST https://api.screenshotrun.com/v1/screenshots \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"proxy": "http://user:[email protected]:8080"
}'
Combining emulation parameters
Dark mode dashboard in Tokyo
curl -X POST https://api.screenshotrun.com/v1/screenshots \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/dashboard",
"dark_mode": true,
"timezone": "Asia/Tokyo",
"full_page": true,
"format": "webp"
}'
Geo-restricted content with full spoofing
Combine proxy (for IP-based detection), geolocation (for browser API), and timezone (for date formatting) to fully emulate a user in a specific location.
curl -X POST https://api.screenshotrun.com/v1/screenshots \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"proxy": "http://user:[email protected]:8080",
"geolocation": {
"latitude": 40.7128,
"longitude": -74.0060
},
"timezone": "America/New_York",
"stealth": true
}'