How to Send Custom HTTP Headers with a Screenshot API
Send target-page headers safely, authenticate private pages, debug 401 screenshots, and choose between hosted APIs and Playwright.
Put the target page’s headers in the screenshot provider’s documented header option, and put your screenshot-service credential in the provider’s authentication header. These are two separate HTTP conversations with different credentials and scopes.
Your application calls the screenshot service. The service’s browser or renderer then calls the target URL. A successful response from the first conversation does not prove that the renderer authenticated to the second one.
1. The request model
Your application
│ API key for screenshot service
▼
Screenshot API
│ Authorization, cookies, Referer, language, etc. for target page
▼
Target page and its subresources
│
▼
PNG, JPEG, WebP, or PDF response
Keep these values separate:
| Value | Where it belongs | Example |
|---|---|---|
| Screenshot-service credential | The request from your application to the screenshot API | Authorization: Bearer SCREENSHOT_API_KEY |
| Target-page credential | The provider’s documented header, cookie, or session option | Authorization: Bearer TARGET_TOKEN |
| Rendering preferences | Target-page headers or provider options | Accept-Language: en-US |
Never assume that a field called headers has the same shape at every vendor. Screenshot API.net documents repeatable header=Name: value parameters, while ScreenshotCenter documents one JSON object per header. Screenshot API.org documents GET and POST capture modes and bearer or X-API-Key authentication in the request headers.
2. cURL with repeated target headers
Screenshot API.net’s documented pattern uses one Authorization header for the service and repeated header parameters for the captured page:
curl -G 'https://screenshot-api.net/v1/screenshot' \
-H "Authorization: Bearer $SCREENSHOT_API_KEY" \
--data-urlencode 'url=https://example.com/account' \
--data-urlencode 'header=Authorization: Bearer target-token' \
--data-urlencode 'header=Accept-Language: en-US' \
-o shot.png
--data-urlencode matters when a header contains spaces, commas, or other reserved characters. Replace the example endpoint and fields with the exact syntax in your provider’s documentation.
Do not put a production screenshot-service key in a browser-visible image URL. Screenshot API.net warns that query-string keys can leak through page source and server logs. Prefer an HTTP authentication header or a server-side proxy.
3. JSON and POST-style providers
Some providers accept a JSON body. ScreenshotCenter shows a header array containing one object per header:
{
"url": "https://example.com/account",
"header": [
{"Authorization": "Bearer target-token"},
{"Accept-Language": "en-US"},
{"X-Request-Id": "abc123"}
]
}
Follow the provider’s exact field names and authentication method. Do not change header to headers, or an array to an object, based on another service’s API.
4. Python
import os
import requests
service_key = os.environ["SCREENSHOT_API_KEY"]
target_token = os.environ["TARGET_TOKEN"]
response = requests.get(
"https://screenshot-api.net/v1/screenshot",
headers={"Authorization": f"Bearer {service_key}"},
params={
"url": "https://example.com/account",
"header": [
"Authorization: Bearer " + target_token,
"Accept-Language: en-US",
"X-Request-Id: abc123",
],
},
timeout=90,
)
response.raise_for_status()
with open("shot.png", "wb") as output:
output.write(response.content)
Some Python clients encode repeated query parameters differently. If your provider expects repeated keys, inspect the final request or pass a list of tuples through the client’s documented parameter mechanism.
5. Node.js
import fs from "node:fs/promises";
const serviceKey = process.env.SCREENSHOT_API_KEY;
const targetToken = process.env.TARGET_TOKEN;
const params = new URLSearchParams();
params.set("url", "https://example.com/account");
params.append("header", `Authorization: Bearer ${targetToken}`);
params.append("header", "Accept-Language: en-US");
params.append("header", "X-Request-Id: abc123");
const res = await fetch(`https://screenshot-api.net/v1/screenshot?${params}`, {
headers: { Authorization: `Bearer ${serviceKey}` },
});
if (!res.ok) throw new Error(`Screenshot API returned ${res.status}`);
await fs.writeFile("shot.png", Buffer.from(await res.arrayBuffer()));
6. ScreenshotNeo request
ScreenshotNeo accepts custom headers, cookies, user agents, and Authorization values for the page being captured. Its API base is https://api.screenshotneo.com/v1/shot. See the ScreenshotNeo API documentation for the current option names and response details.
For a public or authenticated target, send your ScreenshotNeo access key as the service credential and configure target-page headers using the documented option. Keep the two credentials distinct.
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}`);
7. Header scope and common uses
- Authorization and API keys: authenticate the target page when it accepts a bearer token or key.
- Cookies: reproduce an existing session when the provider supports cookie forwarding.
- Referer: satisfy applications that check the referring page; ScreenshotCenter documents a separate
refereroption. - Language: use
Accept-Languageor a provider’saccept_languageoption for localized output. - User agent: select a controlled browser identity where supported. ScreenshotCenter and Screenshots.dev document user-agent controls.
- Correlation IDs: add
X-Request-Idvalues to trace a capture through your application.
Header scope is provider-specific. Screenshots.dev documents custom headers, user agents, authentication credentials, and accept_language. HTML/CSS to Image documents additional_header_origins, which indicates that forwarding headers to asset or API origins may require explicit origin configuration.
Check the main document and protected assets separately. The HTML can load with a token while images, stylesheets, fonts, or XHR requests fail because they use another origin or do not receive the same credentials.
8. Redirects, cookies, and browser state
- Start with the final URL and a short-lived target token.
- Check whether the initial URL redirects to another host or scheme.
- Confirm the provider’s policy for forwarding headers across redirects and origins.
- Use cookie or session support when the application establishes authentication through cookies.
- Remember that headers alone do not perform an interactive login, generate JavaScript tokens, solve a CAPTCHA, or bypass bot defenses.
If the target requires an interactive flow, use a provider with session and browser-automation features or run your own browser workflow.
9. Diagnosing a login page or 401 screenshot
An image response only means the screenshot service produced an image. It may be an error page, a login page, or the intended document. Screenshot API.net exposes X-Page-Status; inspect it before accepting the image.
curl -i -G 'https://screenshot-api.net/v1/screenshot' \
-H "Authorization: Bearer $SCREENSHOT_API_KEY" \
--data-urlencode 'url=https://example.com/account' \
--data-urlencode 'header=Authorization: Bearer target-token' \
-o shot.png
Look for a final status such as 401 or 403, redirect headers, and provider diagnostics. A 401/403 page is an authentication failure even when the API request itself returned HTTP 200 with image bytes.
10. Troubleshooting checklist
| Symptom | Likely cause | Fix |
|---|---|---|
| Provider returns 401 or 403 | Wrong screenshot-service key, endpoint, or authentication header | Test service authentication without target headers, then verify the key and endpoint. |
| Image is a login page | Target Authorization or cookie was not forwarded |
Use the provider’s documented target-header or cookie field; inspect final page status. |
| Header appears ignored | Wrong field shape or URL encoding | Check whether the provider expects repeated query parameters, an array, or an object. Encode spaces and special characters. |
| Initial page works but assets are blank | Assets use another origin or need separate credentials | Configure allowed header origins where supported and test image, CSS, font, and API hosts separately. |
| Authentication works at the first URL but fails after redirect | Headers are restricted or dropped on a different origin | Capture the final host directly or use the provider’s redirect and session controls. |
| Bearer token contains unexpected characters | Shell, URL, or JSON encoding changed the value | Use environment variables, the client encoder, and a short-lived token; never log the raw token. |
| Page requires an interactive login or CAPTCHA | Static headers cannot create browser state or pass bot checks | Use session-capable browser automation or run Playwright. |
11. Playwright fallback
When a hosted provider cannot express the required workflow, Playwright gives your application direct control over browser requests. Its official APIRequest reference exposes extraHTTPHeaders as an object of additional headers sent with every request in that API request context.
import { chromium } from "playwright";
const browser = await chromium.launch();
const context = await browser.newContext({
extraHTTPHeaders: {
Authorization: `Bearer ${process.env.TARGET_TOKEN}`,
"Accept-Language": "en-US",
},
});
const page = await context.newPage();
await page.goto("https://example.com/account", { waitUntil: "networkidle" });
await page.screenshot({ path: "shot.png", fullPage: true });
await browser.close();
A self-managed browser provides more control over redirects, cookies, per-origin routing, and interactive flows. Your application also owns browser versions, rendering resources, concurrency, retries, and secret handling.
12. Performance, reliability, and cost
- Performance: send only the headers required by the target. Large cookies and unnecessary headers increase request size and can complicate caching.
- Reliability: use short-lived target tokens, record a correlation ID, inspect final status, and retry only transient failures. Do not retry authentication failures unchanged.
- Security: keep both service and target credentials server-side, redact them from logs, and scope them to the minimum host and permissions.
- Caching: a cached screenshot may not reflect a newly changed authorization state. Use the provider’s cache controls when you need fresh content.
- Cost: compare whether failed loads, bot checks, blank pages, and cache hits are billable. ScreenshotNeo bills only clean shots; bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and each response identifies the result with
X-Page-VerdictandX-Billedheaders.
13. Or skip the browser setup
ScreenshotNeo handles the hosted capture workflow in one request. Cookie and consent banners are accepted and 60+ known consent platforms, newsletter popups, and chat widgets are removed before the shot; each cleanup step can be turned off. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets Claude, Cursor, and other MCP clients use take_screenshot, get_page_info, and capture_pdf. The Free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000 shots.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Create a free ScreenshotNeo account with 1,000 screenshots per month and no card.
14. FAQ
Should the target token be sent as the screenshot API’s Authorization header?
No. That header normally authenticates your application to the screenshot service. Put the target token in the provider’s documented target-header option.
Are header names case-sensitive?
HTTP field names are generally case-insensitive, but the provider’s parameter names and JSON shape are not. Follow its documented spelling and structure.
Can custom headers replace cookies?
Only when the target accepts header-based authentication. Cookie sessions, CSRF state, JavaScript tokens, and interactive logins may require cookie or browser-session support.
Why does the HTML load while images are missing?
Subresources may use another origin or require credentials that were not forwarded. Check each asset origin and any provider-specific origin allowlist.
When should I run Playwright?
Use it when you need interactive login, JavaScript-generated credentials, CAPTCHA handling, per-origin request routing, or browser state that a hosted header option cannot represent.


