Recommended Free Tools
Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Pass headers to the screenshot provider as rendering options, not as headers on your own call to the provider. For ScreenshotOne, add one URL-encoded headers parameter for each target-page header, for example headers=Authorization: Bearer TOKEN and headers=X-API-Key: key. For larger or more sensitive payloads, send the same options as JSON in a POST request. The provider then applies those headers inside the browser that loads the target page.
What a custom header actually does
A screenshot request has two different HTTP conversations:
- Your application calls the screenshot service and authenticates with that service’s access key or token.
- The service’s browser requests the target URL and renders the response into an image or PDF.
A header added to conversation one is not automatically forwarded to conversation two. Put target-page headers in the provider’s documented rendering option. This distinction explains why adding -H "Authorization: ..." to a request sent to the screenshot API often fails to authenticate the page.
Use a target header when the page expects bearer authentication, an API key, tenant or request ID, a preview flag, or another server-side value. Treat both your screenshot-service credential and the target-page credential as secrets.
#1 Best Overall
ScreenshotOne: GET with one or more headers
ScreenshotOne expresses a header as Header-Name:Header-Value. Repeat the headers query parameter for additional headers. Encode spaces, colons, and other reserved characters before sending the URL.
https://api.screenshotone.com/take?access_key=ACCESS_KEY&url=https%3A%2F%2Fexample.com&headers=Authorization%3A%20Bearer%20TOKEN&headers=X-Request-ID%3A%20123
The example sends two headers to example.com: an Authorization bearer token and an X-Request-ID. Do not concatenate multiple headers into one value; each header gets its own repeated parameter.
cURL
curl -G "https://api.screenshotone.com/take"
--data-urlencode "access_key=$SCREENSHOTONE_ACCESS_KEY"
--data-urlencode "url=https://example.com/account"
--data-urlencode "headers=Authorization: Bearer $TARGET_TOKEN"
--data-urlencode "headers=X-API-Key: $TARGET_API_KEY"
-o account.png
--data-urlencode prevents a space in Bearer TOKEN, a colon in a header, or characters in the page URL from corrupting the query string. Keep values in environment variables rather than shell history or source code.
Python
import os
import requests
params = [
("access_key", os.environ["SCREENSHOTONE_ACCESS_KEY"]),
("url", "https://example.com/account"),
("headers", f"Authorization: Bearer {os.environ['TARGET_TOKEN']}"),
("headers", f"X-API-Key: {os.environ['TARGET_API_KEY']}"),
]
response = requests.get("https://api.screenshotone.com/take", params=params, timeout=90)
response.raise_for_status()
with open("account.png", "wb") as image:
image.write(response.content)
Using a list of tuples preserves duplicate headers keys. A dictionary cannot represent two values for the same key reliably.
Node.js
const accessKey = process.env.SCREENSHOTONE_ACCESS_KEY;
const targetToken = process.env.TARGET_TOKEN;
const targetApiKey = process.env.TARGET_API_KEY;
const params = new URLSearchParams();
params.set('access_key', accessKey);
params.set('url', 'https://example.com/account');
params.append('headers', `Authorization: Bearer ${targetToken}`);
params.append('headers', `X-API-Key: ${targetApiKey}`);
const response = await fetch(`https://api.screenshotone.com/take?${params}`);
if (!response.ok) throw new Error(`Screenshot failed: ${response.status}`);
const data = Buffer.from(await response.arrayBuffer());
require('node:fs').writeFileSync('account.png', data);
Authenticated pages: Authorization, X-API-Key, and cookies
Bearer Authorization
The documented form is headers=Authorization: Bearer <your authentication token>. The token is sent to the target page, not used as the screenshot service’s access_key.
https://api.screenshotone.com/take?access_key=<your access key>&url=https://example.com&headers=Authorization:%20Bearer%20<your authentication token>
ScreenshotOne also documents an authorization=Bearer <token> option. Prefer the provider’s header syntax when you need several custom headers or want the exact wire representation.
X-API-Key
Send an API key as headers=X-API-Key: YOUR_KEY. Header names are case-insensitive, but the spelling and expected value format must match the target application’s contract.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Cookie-authenticated applications
If the application authenticates with a session cookie, supply the cookie through the provider’s cookie option instead of inventing an Authorization header. A site can require both a cookie and a custom header; configure both and verify that the session is valid for the requested host.
Precedence and overrides
ScreenshotOne states: “Headers can override all other previously implicitly set headers by options like cookies or authorization.” This matters when you set the same credential in two places: the explicit header can win, producing a different result from the cookie or authorization option.
When POST JSON is the safer integration
GET is convenient for short URLs and simple jobs, but query strings can expose credentials in logs, traces, browser history, and proxy records. Use POST JSON when the option set is large, when you send HTML or Markdown, or when you want secrets out of the URL. ScreenshotOne documents a maximum POST body size of 100 MiB.
Rank #3
curl -X POST "https://api.screenshotone.com/take"
-H "Content-Type: application/json"
-d '{
"access_key": "ACCESS_KEY",
"url": "https://example.com/account",
"headers": [
"Authorization: Bearer TARGET_TOKEN",
"X-API-Key: TARGET_KEY"
]
}'
-o account.png
Confirm the current POST schema in the provider’s documentation before shipping: providers differ on whether headers are an array, object, or repeated field. Never log the complete JSON body if it contains credentials.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Browserless: headers inside a POST screenshot job
Browserless exposes a POST /screenshot REST endpoint. Its service token is a query parameter; the request body is JSON containing the target URL and an options object. The response can be PNG, JPEG, or WebP according to the selected type.
curl -X POST 'https://production-sfo.browserless.io/screenshot?token=YOUR_API_TOKEN'
-H 'Content-Type: application/json'
-d '{"url":"https://example.com/","options":{"fullPage":true,"type":"png"}}'
--output screenshot.png
Browserless also documents launch parameters for REST calls to /screenshot, /pdf, /content, and /scrape. Check its current API reference for the exact location and shape of a custom-header option before implementing it; do not assume ScreenshotOne’s repeated query syntax applies to Browserless.
Designing a reliable header-enabled capture
Encode and validate
- URL-encode the target URL and every header value in a GET request.
- Preserve repeated keys; use a tuple list in Python and
appendin JavaScript. - Reject newline characters in header names and values to prevent request splitting.
- Allow only headers your application explicitly needs. Do not forward a browser’s entire header dump.
Protect credentials
- Read provider keys and target credentials from environment variables or a secrets manager.
- Prefer POST when long-lived credentials would otherwise appear in query logs.
- Use narrowly scoped, short-lived target tokens where the target system supports them.
- Redact Authorization, API-key, Cookie, and Set-Cookie values from application logs and error reports.
Make the page deterministic
Authentication alone does not guarantee the desired image. The page may redirect to a login screen, render after JavaScript, or require a tenant header. Configure the provider’s documented wait, viewport, full-page, script, style, and resource settings as needed. Keep a non-secret request ID in the headers so you can correlate a failed capture with server logs.
Common failures and fixes
The screenshot shows a login page
Cause: the header was sent to the screenshot service rather than the target browser, the token is expired, or the target redirects to another host. Fix: put the credential in the provider’s rendering option, check the redirect chain, and issue a token valid for the final host and path.
Free tools Windows power users keep installed
One-click scans. No signup required.
Only the first custom header arrives
Cause: duplicate query keys were collapsed by a dictionary, framework, or proxy. Fix: use repeated headers parameters and verify the final encoded URL; in Python use tuples and in Node use params.append.
401 or 403 despite a valid credential
Cause: wrong scheme, missing tenant or API-key header, cookie-only authentication, an IP allow-list, or a token scoped to a different audience. Fix: reproduce the target request with the same method and headers outside the screenshot service, then add only the required values to the capture.
Malformed URL or unexpected header value
Cause: an unescaped space, colon, ampersand, or percent sign changed query parsing. Fix: use --data-urlencode, a URL-parameter library, or URLSearchParams; never hand-concatenate secrets.
GET works locally but fails in production
Cause: production logs, gateways, or WAF rules reject long URLs or expose credentials. Fix: switch to POST JSON, shorten the option set, and update secret-redaction rules.
Capture times out or is blank
Cause: the authenticated page depends on a delayed API call, a blocked third-party resource, or a challenge page. Fix: add the provider’s documented wait condition or delay, test the page without the screenshot service, and inspect the provider’s status and error response. A credential cannot solve a page that never finishes rendering.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Choosing an API approach
| Need | Practical choice | Reason |
|---|---|---|
| One URL and a few headers | ScreenshotOne GET | Readable request and repeated headers parameters. |
| Many options, HTML/Markdown, or less secret exposure | ScreenshotOne POST | JSON body and documented 100 MiB maximum. |
| Existing browser-automation stack | Browserless POST | JSON screenshot jobs and separate launch parameters. |
| Need a managed API with clean captures and predictable billing | ScreenshotNeo | Cookie and popup handling, only clean shots billed, and a $5 paid entry plan. |
Compare providers on header expression, service authentication, target-page authentication, browser controls, output formats, errors, rate limits, caching, and total cost. Limits and syntax can change, so verify the live provider documentation before release.
Or skip the browser setup
ScreenshotNeo accepts custom headers directly while it loads the target page. It also accepts cookies, user agents, Authorization, wait rules, scripts, CSS, device settings, full-page capture, and PDF options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for the header option and the other capture parameters. Cookie banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and each response identifies the page verdict and billing result with X-Page-Verdict and X-Billed headers. Its MCP server lets Claude, Cursor, and other MCP clients call take_screenshot, get_page_info, and capture_pdf. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Sign up free.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsOperational checklist
- Confirm the target’s exact authentication mechanism and final redirect host.
- Put target headers in rendering options, not only in client request headers.
- Encode every GET value and preserve duplicate header parameters.
- Use POST for large payloads or sensitive, long-lived values.
- Keep provider and target credentials out of source control, URLs, and logs.
- Test success, expired-token, redirect, blank-page, timeout, and rate-limit cases.
- Record non-secret request IDs and provider response headers for diagnosis.
Frequently Asked Questions
Can I send an Authorization header and an API key together?
Yes. Send each as its own documented header option; with ScreenshotOne, repeat the headers query parameter.
Does a header on my cURL request automatically reach the website?
No. It authenticates your call to the screenshot service unless that service explicitly maps it to the target browser request.
Should I use a cookie or an Authorization header?
Use the mechanism the target application requires. Cookie sessions need cookies; bearer-token APIs need Authorization. Some applications require both.
Is GET or POST more secure for credentials?
POST keeps long values out of the query string, but you still need HTTPS, secret redaction, and careful request-body logging.
The Bottom Line
Define custom headers in the screenshot provider’s browser-rendering options, encode them correctly, and preserve one parameter per header. Use POST for larger or more sensitive jobs, test redirects and authentication failures, and keep every credential private.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

