How to Add Custom Headers to Screenshot API Requests
Learn how screenshot APIs send custom headers to target pages, with runnable examples, origin and redirect guidance, troubleshooting, and a ScreenshotNeo option.
To add custom headers to a screenshot API request, configure the screenshot provider’s target-page rendering header option. That tells the provider’s remote browser what headers to send while loading the page. A header used to authenticate your request to the screenshot API is a separate thing; do not assume it will be forwarded to the page being captured.
Header option names and formats vary by provider. Check the selected provider’s official API reference for the correct option, encoding, and forwarding scope. For example, one service documents a URL-encoded query parameter, another a JSON object, and another has controls for which origins and subrequests receive headers. HTML/CSS to Image documentation, Screenshots.Dev documentation, and ScreenshotCenter help describe their respective approaches.
Keep API authentication and target-page headers separate
A screenshot call may involve two HTTP conversations:
- Your application sends a request to the screenshot provider. It may include a provider API key or other service authentication.
- The provider’s browser loads the target URL. This is where a target-page header such as
AuthorizationorX-Request-Idmust be configured.
Authentication shown for the screenshot API itself does not establish that the same header is sent to the target page. For example, documentation for Screenshot API (screenshot-api.org) describes Authorization: Bearer … and X-API-Key for its API call; verify target-header support separately in the chosen service’s own reference.
Choose the target-page header option your provider documents
Before writing code, identify the page’s expected header and consult the provider’s documentation. Confirm the option name and whether the endpoint accepts GET query parameters, a POST body, or both. Do not copy an encoding from another vendor.
| Provider example | Documented shape or behavior | What to verify |
|---|---|---|
| HTML/CSS to Image | A headers parameter adds headers when the API loads a page from url. |
The requested URL’s origin is allowed by default. For a different origin, list it in additional_header_origins. Headers reach subrequests such as CSS, images, and JavaScript only when include_headers_on_subrequests is enabled. |
| Screenshots.Dev | headers is a semicolon-separated list of key-value pairs, URL encoded when used in a query. |
Use its documented query encoding and keep its separate cookie option distinct. |
| ScreenshotCenter | Its help page shows custom HTTP headers as JSON objects in a header array. |
Follow its documented JSON request shape. |
These are provider-specific examples, not interchangeable formats or a universal standard. A generic illustrative JSON shape might look like this, but use it only if your provider documents that exact format:
{
"url": "https://example.com/private-page",
"headers": {
"Authorization": "Bearer TARGET_PAGE_TOKEN",
"X-Request-Id": "capture-123"
}
}
Implement the request for your provider
- Write down the target URL and the header names and values the page expects.
- Find the provider’s documented target-render header option and request method.
- Check whether the header applies to the main document, redirects, and subresources on other origins.
- Send a controlled capture request and inspect whether the rendered result reflects the authenticated page. This is a recommended verification step, not a claim that a request was tested for this guide.
Because the format differs by provider, there is no honest universal runnable request to give for an unspecified screenshot API. Adapt the following templates to the provider’s official option name, encoding, endpoint, and authentication method.
cURL template
# Replace the endpoint and query parameter with the provider's documented format.
curl -G "https://SCREENSHOT_PROVIDER_ENDPOINT" \
-H "Authorization: Bearer SCREENSHOT_PROVIDER_KEY" \
--data-urlencode "url=https://example.com/private-page" \
--data-urlencode 'headers={"Authorization":"Bearer TARGET_PAGE_TOKEN","X-Request-Id":"capture-123"}' \
-o capture.png
This is a template, not a format accepted by every provider. Some providers require a POST JSON body or a differently encoded header value.
Python template
import requests
endpoint = "https://SCREENSHOT_PROVIDER_ENDPOINT"
params = {
"url": "https://example.com/private-page",
# Replace with the exact documented option and encoding.
"headers": '{"Authorization":"Bearer TARGET_PAGE_TOKEN",'
'"X-Request-Id":"capture-123"}',
}
response = requests.get(
endpoint,
params=params,
headers={"Authorization": "Bearer SCREENSHOT_PROVIDER_KEY"},
timeout=90,
)
response.raise_for_status()
with open("capture.png", "wb") as image_file:
image_file.write(response.content)
If the provider documents a POST body, use its specified JSON structure with requests.post instead of assuming the GET template applies.
Node.js template
const endpoint = new URL('https://SCREENSHOT_PROVIDER_ENDPOINT');
endpoint.searchParams.set('url', 'https://example.com/private-page');
// Replace this parameter name and value format with the provider's documented form.
endpoint.searchParams.set(
'headers',
JSON.stringify({
Authorization: 'Bearer TARGET_PAGE_TOKEN',
'X-Request-Id': 'capture-123',
}),
);
const response = await fetch(endpoint, {
headers: { Authorization: 'Bearer SCREENSHOT_PROVIDER_KEY' },
});
if (!response.ok) {
throw new Error(`Screenshot request failed: ${response.status} ${response.statusText}`);
}
const image = Buffer.from(await response.arrayBuffer());
await import('node:fs/promises').then(({ writeFile }) => writeFile('capture.png', image));
Origin, redirect, and resource scope
Headers may be restricted to the requested page’s origin. A page can redirect to another origin, and its scripts, stylesheets, images, or API calls can load from yet other origins. A provider may intentionally avoid forwarding credentials to those locations.
- Check documented origin allowlists and subrequest switches.
- Scope sensitive headers to only the origin that needs them. This follows from the documented origin-scoping behavior and limits accidental credential forwarding.
- Do not assume a header reaches a redirect destination or every resource. Verify each behavior against the provider’s reference.
- If the page’s main HTML loads but its content is missing, check whether the content depends on authenticated subrequests.
Security and credential handling
- Use a target-page token with the minimum access needed for the capture.
- Keep provider API credentials and target-page credentials in server-side configuration, not browser code or public URLs.
- Query-string options may be recorded in logs. If a provider offers a POST body or another safer credential path, follow its documentation and your organization’s handling rules.
- Allow headers on additional origins only when the target flow requires it.
- Avoid capturing sensitive pages into publicly accessible storage or links unless access controls are in place.
Common errors and fixes
| Symptom | Likely cause | What to check |
|---|---|---|
| The screenshot shows a login page or an access-denied page. | The target header was omitted, malformed, or attached as screenshot-service authentication instead. | Use the documented target-render option and check the header name, value, and encoding. |
| The main page loads, but images or dynamic content are missing. | Authenticated subrequests need the header, but forwarding to subrequests is disabled or restricted. | Check the provider’s subrequest controls and allowed origins. |
| Headers work on the original URL but fail after navigation. | A redirect changes origin or the provider restricts forwarding. | Inspect the redirect destination and provider rules; do not broaden credential forwarding without need. |
| The provider rejects the request or ignores the header option. | The option name, value shape, or encoding does not match that provider’s endpoint. | Compare the exact request method and syntax with the official reference. A JSON object, semicolon-separated value, and URL-encoded query are different formats. |
| The header value is truncated or split. | Reserved characters were not encoded for a query parameter, or shell quoting altered the value. | Use the provider’s encoding guidance and the HTTP client’s parameter encoder; avoid hand-building query strings. |
| The screenshot succeeds but shows stale content. | A cached result may be returned by the provider or the target page. | Check the provider’s cache controls and use a documented cache-bypass or freshness option if available. |
Performance, reliability, and cost considerations
Custom headers do not by themselves guarantee a successful capture. The target must accept the credentials, the provider must forward them to the relevant origin and resources, and the page must finish loading. Redirects and client-side requests can add dependencies. Use a bounded timeout and inspect the provider’s documented response and error behavior.
For repeat captures, check whether the provider supports caching and whether cache keys distinguish requests with different target credentials. Do not assume that two captures with the same URL but different headers can safely share a cached result. Confirm the provider’s cache semantics before caching authenticated pages.
Costs and limits are provider-specific. Review per-capture pricing, retries, concurrency limits, timeout behavior, and whether unsuccessful or cached requests are billed. The reviewed provider documentation establishes differences in header format and forwarding scope; it does not support a universal cost or performance comparison.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server for developers. It supports custom headers, cookies, user agents, and Authorization for a target page. One GET request returns PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API 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}`);
To send a target-page header, add the documented custom-header option for ScreenshotNeo to the request; keep the target credential distinct from access_key, which authenticates the ScreenshotNeo API. Refer to the docs for the exact parameter format.
- Cookie banners, popups, and chat widgets are removed before the shot; each cleanup step can be turned off.
- Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed. Response headers identify the page verdict and billing status.
- An MCP server lets Claude, Cursor, and other MCP clients take screenshots using
take_screenshot,get_page_info, andcapture_pdf. - 1,000 screenshots a month are free with no card; paid plans start at $5 for 3,000. Every feature is on every plan.
Sign up for ScreenshotNeo and get 1,000 free screenshots a month, with no card required.
FAQ
Can I pass an Authorization header to the captured page?
Yes, if the selected screenshot service documents target-page custom headers. Configure it as a rendering option and confirm the allowed origin and subrequest behavior.
Will the target header be sent to every page resource?
Not necessarily. Providers can restrict forwarding by origin and by whether the request is for the main document or a subresource.
Can I use the same header parameter with every screenshot API?
No. Option names, encodings, and request methods vary. Use the selected provider’s API reference.
Should I put a target token in the URL?
Only if the provider requires that documented format and you have accounted for URL and request logging. Keep credentials server-side and scope them to the required origin.


