CaptureKit screenshot API authentication error: how to fix it
Fix CaptureKit screenshot API authentication errors by checking the status, error body, API key, endpoint, and rate limit before changing your request.
Start with the HTTP status and JSON response body. CaptureKit documents x-api-key as its authentication header, but a 401 can mean an invalid or missing key, an inactive or expired key, or a rate limit. Read the error message before changing credentials or retrying. [CaptureKit Error Handling]
1. Read the status and error body
Check both the HTTP status and the response body. A status by itself may not tell you whether the problem is credentials or request volume. CaptureKit’s error guide says the body contains a human-readable error description.
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{"error":"Your x-api-key header is missing or contains an unrecognized value."}
Use the exact message to choose the next step. Repair the request or key for an authentication error; back off for a rate-limit response. Do not blindly retry an authentication failure. [Error Handling]
2. Confirm the documented authentication format
For current integrations, send the API key in the x-api-key request header. Copy the key from the API Keys area of your CaptureKit dashboard. Check for:
- A missing header or a misspelled header name. Header names are conventionally case-insensitive, but use the documented spelling.
- A value copied with leading or trailing whitespace, quotation marks, or a newline.
- A key from the wrong account, an old key, or a placeholder that was never replaced.
- Code that sets a different header than the one actually sent by the HTTP client.
CaptureKit also documents x_api_key as a query-string option. Prefer the header for new integrations, since URL query strings can be recorded in logs and intermediaries. Keep the key server-side and out of public repositories and browser code. [CaptureKit Introduction]
3. Verify the key independently with cURL
Test authentication against CaptureKit’s free /v1/usage endpoint before debugging screenshot parameters. This isolates the credential check from capture options. [CaptureKit Quick start]
export CAPTUREKIT_API_KEY='YOUR_API_KEY'
curl -i 'https://api.capturekit.dev/v1/usage' \
-H "x-api-key: ${CAPTUREKIT_API_KEY}"
Inspect the status and response body. If this check fails with an authentication message, fix the key or header first. If it succeeds, compare the screenshot request’s endpoint and authentication format with the current documentation.
4. Verify the key from Python
This runnable example reads the secret from an environment variable and prints the status and response body for diagnosis:
import os
import requests
api_key = os.environ["CAPTUREKIT_API_KEY"]
response = requests.get(
"https://api.capturekit.dev/v1/usage",
headers={"x-api-key": api_key},
timeout=30,
)
print("HTTP", response.status_code)
print(response.text)
Install the dependency with python -m pip install requests. Do not print or log the key itself. For production code, handle network exceptions and parse JSON only after confirming the response format.
5. Verify the key from Node.js
With Node.js 18 or later, the built-in fetch can make the same independent check:
const apiKey = process.env.CAPTUREKIT_API_KEY;
if (!apiKey) throw new Error('Set CAPTUREKIT_API_KEY first');
const response = await fetch('https://api.capturekit.dev/v1/usage', {
headers: { 'x-api-key': apiKey },
signal: AbortSignal.timeout(30_000),
});
console.log('HTTP', response.status);
console.log(await response.text());
Run it with CAPTUREKIT_API_KEY='YOUR_API_KEY' node verify.mjs. Keep this check in a server-side environment; do not embed the secret in frontend JavaScript.
6. Check key status and request version
If the usage check reports an authentication error, go to the dashboard’s API Keys area and confirm the key is valid, active, and not expired. Activate an inactive key, extend an expired key if possible, or generate a replacement for a missing or unrecognized key. Update the secret in your deployment environment after rotating it. [Introduction]
Also check whether the integration uses a legacy request format. CaptureKit’s February 19, 2026 migration notice describes versioned /v1/ paths and x_api_key in place of the former access_key; it shows the screenshot route as /v1/capture. Current introduction documentation specifies the x-api-key header and also lists x_api_key as a query parameter. When maintaining older code, use the exact endpoint documentation for that request; for a new request, use the current documented format. [Migration notice, Introduction]
7. Distinguish rate limiting from bad credentials
CaptureKit may return 401 for rate limiting as well as authentication errors. If the response message identifies a rate limit or quota, reduce request frequency and retry after a delay. Use backoff that grows between attempts and add jitter when many workers retry together. If limits are reached regularly, review the applicable plan or per-key quota. If the message identifies a missing, invalid, inactive, or expired key, correct the credential instead of retrying. [Error Handling]
Do not assume that every 401 means the same thing, and do not run a tight retry loop: it can make a rate-limit problem worse.
8. Review API Logs
Find the failed request by its timestamp in CaptureKit API Logs. Check the recorded request details and returned error to see whether the header arrived, which endpoint was called, and what response came back. This helps distinguish code that constructs the wrong request from a key or account-state issue. [CaptureKit documentation help center]
Common errors and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
401 says the key is missing or unrecognized |
Missing or misspelled x-api-key, wrong key, placeholder, or copied whitespace |
Send the dashboard key in the documented header; verify it with /v1/usage. |
401 says the key is inactive or expired |
The key cannot authenticate in its current state | Activate or extend it, or generate a new key and update the environment where the app runs. |
401 mentions a rate limit or quota |
Request volume exceeded the applicable limit | Back off, reduce concurrency, and review plan or per-key limits if it recurs. |
| Usage succeeds, screenshot call fails | The screenshot call may use a different header, old path, or obsolete key parameter | Compare the actual request with current endpoint docs and inspect API Logs. |
| Works locally but fails after deployment | Deployment secret missing, stale, or configured under a different variable name | Set the key in the deployed service’s secret configuration and restart or redeploy as required by that platform. |
| Intermittent failures under load | Rate limiting or synchronized retries | Cap concurrency, apply exponential backoff with jitter, and avoid retrying credential errors. |
Reliability, security, and cost notes
- Check before capture: use the free usage endpoint to verify credentials independently, so screenshot parameters do not obscure an auth failure.
- Keep secrets private: use environment or secret-manager configuration, rotate exposed keys, and avoid query-string credentials where possible.
- Retry selectively: a rate limit calls for delayed retry; an invalid, inactive, or expired key needs correction. Avoid retry storms.
- Watch actual request outcomes: use API Logs to diagnose failed calls before changing multiple variables at once.
- Cost: the cited CaptureKit material establishes that
/v1/usageis free, but does not establish screenshot prices or billing behavior for failed requests. Check the current plan details before estimating capture costs.
Or skip the browser setup
If the goal is to get a screenshot rather than maintain capture infrastructure, ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. It uses a single GET request; see the ScreenshotNeo API documentation for options and setup.
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}`);
- Cookie banners are accepted like a visitor would accept them, then removed along with 60+ known consent platforms, newsletter popups, and chat widgets before the shot. Each step can be turned off.
- Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed; response headers identify the page verdict and billing status.
- An MCP server provides
take_screenshot,get_page_info, andcapture_pdftools for Claude, Cursor, and other MCP clients. - The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Every feature is available on every plan.
Sign up for ScreenshotNeo free: 1,000 screenshots a month, no card required.
FAQ
Does a 401 always mean my API key is wrong?
No. CaptureKit also uses 401 for rate limiting. The error body tells you whether to repair credentials or back off.
Can I put the key in a URL query parameter?
CaptureKit documents x_api_key as a query-string option, but the documented x-api-key header is preferable for new integrations because URLs can be captured in logs.
What is the quickest authentication-only check?
Call https://api.capturekit.dev/v1/usage with the x-api-key header, then inspect the response and matching API Log entry.
Should I retry an invalid-key response?
No. Fix or replace the key first. Retry with backoff only when the response identifies rate limiting or another temporary condition.


