How to Set a Custom User Agent in a Website Screenshot API
Set a screenshot API’s documented user-agent option, then verify it independently from viewport and device settings. Here are provider examples, limits, and fixes.
Set the user agent with the screenshot provider’s documented option. The field name and request format vary: Cloudflare Browser Run uses userAgent in a JSON body, while ScreenshotOne documents user_agent as a request parameter. A user-agent string describes the requesting software to servers; it does not set viewport dimensions, device scale, touch behavior, or browser engine, and it does not guarantee access past bot protections. See the MDN User-Agent header reference.
Choose the right setting
First identify the exact screenshot endpoint and its transport format. Use its dedicated user-agent setting with the documented spelling and casing. If the service also offers generic extra headers, do not assume that setting User-Agent there is equivalent; check the provider’s documentation.
| Provider or tool | Documented setting | Important detail |
|---|---|---|
| Cloudflare Browser Run screenshot endpoint | userAgent in the JSON body |
Cloudflare says the setting does not bypass bot protection; requests remain identifiable as bot traffic through headers that cannot be changed. Endpoint documentation. |
| Cloudflare Browser Rendering screenshot API | userAgent |
The schema lists this separately from setExtraHTTPHeaders and viewport configuration. API reference. |
| ScreenshotOne | user_agent request parameter |
The documented default is the latest browser version used by Puppeteer. Its viewport_device option overrides user_agent; changing the user agent may affect stealth-mode capabilities. Options documentation. |
| shot-scraper local CLI | --user-agent TEXT |
A local capture option; its documentation lists Chromium, Firefox, WebKit, Chrome, and Chrome Beta support. Documentation. |
Other APIs, including Screenshots.Dev, ScreenshotRun, Screenshot Machine, and ScreenshotCenter, also document user-agent parameters. Verify their current field names and encoding before adapting an example: provider syntax is not a shared standard. See the Screenshots.Dev docs, ScreenshotRun device docs, and Screenshot Machine API.
Send a custom user agent to Cloudflare Browser Run
This illustrative request uses the documented userAgent JSON field. The example string is a placeholder; choose a truthful, descriptive value suited to a legitimate compatibility test. It is not a tested request, and changing the value does not turn an automated capture into a normal browser visit.
curl -X POST "https://api.cloudflare.com/client/v4/accounts/ACCOUNT_ID/browser-rendering/screenshot" \
-H "Authorization: Bearer CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{"url":"https://example.com/","userAgent":"Mozilla/5.0 (compatible; ExampleBot/1.0)"}' \
--output screenshot.png
Replace ACCOUNT_ID and the token with credentials for your account, and confirm the current endpoint and required permissions in Cloudflare’s documentation before use. The example shows the JSON field and transport shape; it does not claim a particular response, authorization scope, or successful capture.
Python with the JSON request shape
import requests
endpoint = "https://api.cloudflare.com/client/v4/accounts/ACCOUNT_ID/browser-rendering/screenshot"
payload = {
"url": "https://example.com/",
"userAgent": "Mozilla/5.0 (compatible; ExampleBot/1.0)",
}
response = requests.post(
endpoint,
headers={
"Authorization": "Bearer CLOUDFLARE_API_TOKEN",
"Content-Type": "application/json",
},
json=payload,
timeout=90,
)
response.raise_for_status()
with open("screenshot.png", "wb") as image_file:
image_file.write(response.content)
Use the response handling expected by the endpoint you call. If the API returns JSON metadata rather than image bytes, parse that response and retrieve the image according to its documented workflow instead of saving JSON as a PNG.
Node.js with fetch
const endpoint = 'https://api.cloudflare.com/client/v4/accounts/ACCOUNT_ID/browser-rendering/screenshot';
const response = await fetch(endpoint, {
method: 'POST',
headers: {
Authorization: 'Bearer CLOUDFLARE_API_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: 'https://example.com/',
userAgent: 'Mozilla/5.0 (compatible; ExampleBot/1.0)',
}),
});
if (!response.ok) {
throw new Error(`Screenshot request failed: ${response.status} ${response.statusText}`);
}
const bytes = new Uint8Array(await response.arrayBuffer());
await Bun.write('screenshot.png', bytes);
This save step uses Bun’s Bun.write. In Node.js, replace the last two lines with const fs = await import('node:fs/promises'); await fs.writeFile('screenshot.png', Buffer.from(bytes));.
Set ScreenshotOne’s user-agent parameter
ScreenshotOne documents the user_agent request parameter and shows the value screenshoter as an example. The following cURL request illustrates the parameter’s query-string form; use your own API key and check the current options documentation for the correct endpoint and any required parameters.
curl -G "https://api.screenshotone.com/take" \
--data-urlencode "access_key=YOUR_API_KEY" \
--data-urlencode "url=https://example.com/" \
--data-urlencode "user_agent=Mozilla/5.0 (compatible; ExampleBot/1.0)" \
-o screenshot.png
Python
import requests
response = requests.get(
"https://api.screenshotone.com/take",
params={
"access_key": "YOUR_API_KEY",
"url": "https://example.com/",
"user_agent": "Mozilla/5.0 (compatible; ExampleBot/1.0)",
},
timeout=90,
)
response.raise_for_status()
with open("screenshot.png", "wb") as image_file:
image_file.write(response.content)
Node.js
const params = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://example.com/',
user_agent: 'Mozilla/5.0 (compatible; ExampleBot/1.0)',
});
const response = await fetch(`https://api.screenshotone.com/take?${params}`);
if (!response.ok) {
throw new Error(`Screenshot request failed: ${response.status} ${response.statusText}`);
}
const fs = await import('node:fs/promises');
await fs.writeFile('screenshot.png', Buffer.from(await response.arrayBuffer()));
These provider examples show the documented field shape, not independently verified live requests. Check the provider’s current endpoint, authentication, output behavior, and option precedence before deploying. Avoid putting API keys in shared URLs or logs.
Keep user agent and device emulation separate
A User-Agent header is one input to server-side content selection. It does not itself resize the page or change the browser’s input behavior. For a mobile-layout comparison, set the viewport and any supported mobile, touch, device-preset, or device-scale settings separately. Cloudflare’s screenshot API exposes viewport configuration, and ScreenshotOne documents viewport and device-scale options. A device preset can also take precedence: ScreenshotOne says viewport_device overrides user_agent.
- Testing server variation: change the user-agent string, keep other capture settings fixed, and compare results.
- Testing responsive layout: change viewport dimensions as needed; do not infer layout from the user-agent string.
- Testing a device profile: configure the provider’s documented device controls and check whether that preset replaces a custom user agent.
- Testing request headers: use the provider’s separate extra-header setting where documented, and confirm how it treats restricted or special headers.
For a local command-line alternative, shot-scraper documents --user-agent TEXT. Check its current CLI documentation for installation, browser selection, and command syntax.
Verify what the page received
- Use a page or endpoint you control that reports the received request header, or a user-agent checking page referenced by your provider’s documentation.
- Run a baseline capture using the provider default, then repeat with the custom value while keeping the URL and other settings unchanged.
- Inspect the returned page or screenshot and, when available, response metadata. A rendered page alone may not reveal every request header.
- If the result is unexpected, check whether a device preset overrides the custom value, whether the provider applies the setting to the page navigation, and whether the site selects content by other signals too.
A user-agent string can contribute to browser fingerprinting. Use only a value that accurately describes the compatibility condition you intend to test; do not present a fabricated browser or device identity as a way to evade controls. MDN discusses the header’s identification and privacy implications in its reference.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. One GET request takes a URL and returns an image or PDF; its API parameter names also work with the names used by other screenshot APIs, which can make switching easier. For the exact available settings, see the ScreenshotNeo API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com/ \
-o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com/"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://example.com/',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
- Cookie banners are accepted like a visitor and removed before the shot; newsletter popups and chat widgets are removed too. Each step can be turned off.
- Bot checks, blank pages, failed loads, timeouts, and cache hits cost nothing; response headers report the page verdict and whether the request was billed.
- An MCP server provides
take_screenshot,get_page_info, andcapture_pdffor Claude, Cursor, and other MCP clients. - The free plan includes 1,000 screenshots a month with no card. Paid plans start at $5 for 3,000 shots; every feature is on every plan.
Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.
Troubleshooting
| Symptom | Likely cause | What to check |
|---|---|---|
| The page still shows the old content variant | The field name, casing, or encoding is wrong, the option was ignored, or the site does not select content by User-Agent alone. | Copy the provider’s exact option name; confirm the request body or encoded query; verify the value on a page you control. |
| A device preset appears to replace the value | The preset has precedence over the custom option. | Check option precedence. ScreenshotOne documents that viewport_device overrides user_agent. |
| The request is still blocked | A custom user agent is not an access-control bypass. The provider may expose other signals that identify automated traffic. | Read the provider’s bot-protection guidance and use an authorized test environment or site owner-approved access path. Cloudflare explicitly says its Browser Run setting does not bypass bot protection. |
| The screenshot is saved as invalid image data | The endpoint may have returned an error response or JSON instead of image bytes. | Check the HTTP status and content type before saving; follow the endpoint’s documented error and output handling. |
| The request fails with an authorization error | The key, token, account identifier, or required permission may be missing or incorrect. | Confirm credentials and endpoint requirements in the provider’s current documentation. Keep secrets out of source control and logs. |
| Changing the value changes capture behavior | The provider may tie defaults or stealth behavior to its normal browser identity. | Compare with the default. ScreenshotOne warns that overriding its user agent may break stealth-mode capabilities. |
Performance, reliability, and cost
A custom header is a request configuration, not a guarantee of a faster or more reliable render. Capture time and success depend on page loading, provider behavior, and the site’s responses; the research sources provide no comparable benchmark. Use explicit timeouts in client code, inspect status and response type, and retry only transient failures according to the provider’s guidance. Repeated captures may have provider-specific caching behavior, so check whether cache settings affect the response you are comparing.
Costs, limits, and billing rules are provider-specific. Confirm the selected service’s current pricing and whether failed captures or retries are billed. Do not assume that setting a user agent changes billing or guarantees successful delivery.
Frequently asked questions
Does a custom user agent make a screenshot look like a real phone?
No. It changes the user-agent value where the provider supports it. Set viewport and other documented device-emulation controls separately.
Can I use the User-Agent field to get past a CAPTCHA?
No such result is guaranteed. Cloudflare says its configurable value does not bypass bot protection, and a site may use additional signals. Use an authorized access route.
Should I use a browser’s exact production user-agent string?
Use a truthful value that matches the condition you are testing. A copied string alone does not reproduce the browser engine, viewport, touch support, or other device characteristics.
Why is my provider’s parameter named differently?
Screenshot APIs define their own request schemas. Follow the exact field name, casing, and transport format in the documentation for your endpoint.


