ScreenshotNeo

BlogHow-to

Screenshotlayer API Returns 403: How to Troubleshoot Access Errors

A 403 is not assigned a specific cause in Screenshotlayer’s published API errors. Identify which layer returned it, then check the request, key, plan, and network path.

By the ScreenshotNeo team4 October 20269 min read

If the Screenshotlayer API returns 403, do not assume the access key is invalid or the monthly allowance is exhausted. Screenshotlayer’s published API error list does not define an HTTP 403 cause. First determine whether the response is a structured Screenshotlayer error or a bare denial, then check the request, account, and network path.

The documented capture endpoint is https://api.screenshotlayer.com/api/capture. Requests require an access_key and a target url containing http:// or https://. Screenshotlayer documents provider errors as JSON with success: false and an error object containing a code, type, and info message. The published list includes key, function, usage, and URL errors, but no 403-specific entry. See the API specification and FAQ.

1. Identify which layer returned the 403

Save the complete response before changing credentials or retrying. The HTTP status alone does not establish which component rejected the request. A structured body that matches Screenshotlayer’s documented error format gives you a provider error code to investigate. A bare 403, HTML error page, or response branded by a proxy, CDN, firewall, or hosting platform does not establish a Screenshotlayer-specific cause. This distinction is a diagnostic inference from the documented response format; Screenshotlayer does not publish a 403 interpretation.

HTTP status: 403
Response headers: ...
Response body: ...
Request time (UTC): ...
Request URL: https://api.screenshotlayer.com/api/capture?access_key=[REDACTED]&url=https%3A%2F%2Fexample.com

Redact the access key and any sensitive target URL before saving logs or sharing them. Preserve the response headers and body, and note any request or trace ID if present. Do not copy a live key into a browser address bar, screenshot, issue tracker, analytics event, or third-party request tool.

2. Make one controlled request

Use a small diagnostic request to the documented endpoint. Keep the key out of shell history where practical, and avoid printing the full request URL because the key is a query parameter. The examples below save response headers and body separately where the client supports it.

cURL

curl --silent --show-error \
  --get 'https://api.screenshotlayer.com/api/capture' \
  --data-urlencode "access_key=$SCREENSHOTLAYER_ACCESS_KEY" \
  --data-urlencode 'url=https://example.com' \
  --dump-header response-headers.txt \
  --output response-body.bin \
  --write-out '\nHTTP %{http_code}\n'

Set SCREENSHOTLAYER_ACCESS_KEY in your local environment before running the command. Inspect the saved body as text if it appears to be JSON or HTML. A successful capture is an image response, so do not assume every non-JSON body is a useful diagnostic message.

Python

import os
import requests

endpoint = "https://api.screenshotlayer.com/api/capture"
params = {
    "access_key": os.environ["SCREENSHOTLAYER_ACCESS_KEY"],
    "url": "https://example.com",
}

response = requests.get(endpoint, params=params, timeout=60)
print("HTTP status:", response.status_code)
print("Response headers:", dict(response.headers))
print("Content type:", response.headers.get("content-type"))
print("Body preview:", response.text[:2000] if "text" in response.headers.get("content-type", "") or "json" in response.headers.get("content-type", "") else "[binary response]")

if response.ok and response.headers.get("content-type", "").startswith("image/"):
    with open("screenshot", "wb") as output:
        output.write(response.content)

Node.js

const endpoint = new URL('https://api.screenshotlayer.com/api/capture');
endpoint.searchParams.set('access_key', process.env.SCREENSHOTLAYER_ACCESS_KEY);
endpoint.searchParams.set('url', 'https://example.com');

const response = await fetch(endpoint, { signal: AbortSignal.timeout(60_000) });
const contentType = response.headers.get('content-type') || '';
const body = Buffer.from(await response.arrayBuffer());

console.log('HTTP status:', response.status);
console.log('Response headers:', Object.fromEntries(response.headers));
console.log('Content type:', contentType);
if (contentType.includes('json') || contentType.startsWith('text/')) {
  console.log('Body preview:', body.toString('utf8').slice(0, 2000));
} else {
  console.log('[binary response]');
}

if (response.ok && contentType.startsWith('image/')) {
  const { writeFile } = await import('node:fs/promises');
  await writeFile('screenshot', body);
}

These examples use HTTPS. The API specification says HTTPS is available to paid customers, and the pricing page describes HTTPS encryption on paid plans. If your account cannot use HTTPS, check the current plan and account documentation rather than treating an old HTTP example as a recommendation. Never send credentials over an unencrypted connection.

3. Check the endpoint and required parameters

Confirm the request is a GET to /api/capture, with the required access_key and url parameters. The target URL must include its protocol: use https://example.com, not example.com.

  • Check that the application is calling api.screenshotlayer.com, not your own application route or a stale endpoint.
  • URL-encode the target URL. Let a query-parameter encoder do this; manually concatenating a target URL containing &, #, or other reserved characters can truncate or alter it.
  • Check for duplicate parameters, empty values, whitespace, and truncation in configuration or request-building code.
  • Verify the deployed environment reads the intended secret. A local key can differ from the key in a container, CI job, serverless function, or production secret store.

The official specification lists optional capture parameters such as fullpage, width, viewport, format, css_url, delay, ttl, force, placeholder, user_agent, and accept_lang. They configure capture behavior; adding them is not a documented fix for HTTP 403. Start with only the required parameters so the diagnostic request stays easy to inspect.

4. Verify the access key and account

Retrieve the key from the Account Dashboard. If the key may have been copied incorrectly, rotated, or exposed, reset it in the dashboard and update the application’s secret store. Test once with the updated value. Do not expose the key while debugging.

Then inspect the account’s current subscription, monthly usage, notices, and any account-level restriction. Documentation is inconsistent about quota behavior: the API specification lists a usage_limit_reached error, while current pricing material says overage fees apply after 100% of the monthly allowance. Neither source says that quota exhaustion produces a 403. Check the live dashboard and plan terms for your account; do not infer that an HTTP 403 proves a quota problem. See current pricing information and the API error list.

5. Interpret the response carefully

Finding What it establishes Next step
JSON with success: false and an error object A provider-style error response; inspect its documented code, type, and info. Follow the message and check the related request value, key, function, or account usage.
Code 104 and invalid_access_key The specification’s example for an invalid key. Retrieve or reset the key in the dashboard, then update the deployed secret.
Code 101, 103, or 210 The documented list associates these with missing key, invalid API function, or invalid target URL. Correct the corresponding parameter or endpoint; check the actual response wording because the specification’s table has inconsistent descriptions for key errors.
Bare 403, HTML page, or intermediary branding The public API error list does not explain this response or identify its source. Record headers and body; investigate the request path and ask support to identify the rejecting layer.
Different result from different authorized network paths A network-path difference is evidence to investigate, not proof of a particular blocker. Inspect outbound proxy, firewall, DNS, gateway, and hosting-provider controls.

The documented error descriptions and codes come from Screenshotlayer’s published specification. Diagnosing proxies or other intermediaries is a practical inference, not a vendor-confirmed explanation of 403.

6. Isolate network and transport issues

If permitted, send the same sanitized request from the application host and one controlled alternate network. Do not use another person’s account or send a real key through an online request inspector. If one path succeeds and another fails, inspect the failing path’s outbound proxy, firewall rules, DNS resolution, gateway, and hosting-provider controls. If both paths return the same response, that still does not identify the rejecting layer; the response body, headers, and provider support are needed.

Use a small number of deliberate attempts. Repeated retry loops can consume allowance, obscure the first useful response, or encounter usage controls. Add bounded retries only for transient network failures, with backoff and a retry limit; do not automatically retry a persistent 403.

7. Escalate with a safe diagnostic bundle

If the cause remains unclear, contact Screenshotlayer support through its support page. Include:

  • UTC timestamp and the endpoint path.
  • HTTP status, response headers, and response body.
  • Redacted request parameters, including the target host if it is safe to disclose.
  • Account plan and dashboard usage or restriction notices.
  • Whether the result changes across authorized network paths.
  • Any request or trace ID returned in the response.

Never include the raw access key or secret. Screenshotlayer’s published materials do not provide a 403-specific recovery procedure, so a response trace from support may be needed to determine which layer refused the request.

Or skip the browser setup

If the issue is that you need a working screenshot capture flow, ScreenshotNeo is a screenshot API and MCP server. One GET request returns an image or PDF, and you can inspect response headers to see whether a page was captured, blocked, blank, failed, or served from cache. The API documentation has the 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}`);
  • Cookie and consent banners, newsletter popups, and chat widgets are removed before capture; each cleanup step can be turned off.
  • Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed.
  • An MCP server lets AI agents, including Claude and Cursor, use screenshot tools.
  • The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

Sign up free for 1,000 screenshots a month with no card.

Performance, reliability, and cost considerations

For diagnosis, keep requests minimal and avoid automatic retries on 403. This preserves the original evidence and avoids avoidable API usage. For production capture jobs, use a finite timeout, record status and response metadata without credentials, and retry only transient failures with bounded backoff. Confirm how your current Screenshotlayer plan counts requests and handles overages in the dashboard and current terms; the published materials describe both allowance errors and overage billing in different places.

Do not treat an HTTP status alone as an uptime or availability measure. A 403 is a refusal response, but the public documentation does not say which layer generates it. Preserve timestamps and trace identifiers so support can investigate the specific request.

Troubleshooting checklist

Symptom Likely check Action
Missing or invalid key error Absent, mistyped, stale, or wrong-environment key. Retrieve or reset it in the dashboard; update the secret store.
Invalid URL error Missing protocol, malformed URL, or encoding issue. Use a complete https:// URL and encode query parameters.
Usage error or account notice Allowance, subscription status, or account restriction. Check current dashboard usage and plan terms; do not assume this is the source of a 403.
403 with no provider-style JSON Undetermined response source. Save headers/body and UTC time; compare authorized network paths and escalate.
Works locally but fails in deployment Different secret, proxy, DNS, firewall, or outbound policy. Compare redacted configuration and network behavior without logging credentials.
Repeated failures after retries Retry policy hides the original response or adds usage. Stop the loop; make one controlled request and preserve its raw response.

FAQ

Does a 403 prove my Screenshotlayer key is invalid?

No. The published error list does not map HTTP 403 to an invalid key. Check whether the body contains a documented provider error; the specification’s invalid-key example is a JSON error with code 104 and type invalid_access_key.

Does reaching my monthly limit cause a 403?

The available documentation does not establish that. The specification lists a usage-limit error, while current pricing information describes overage fees after the allowance is reached. Check your dashboard and plan terms.

Should I keep retrying the request?

No. First capture the response details. A persistent 403 is not a transient network failure, and repeated requests can consume usage without revealing a new cause.

Can I safely share a failing request with support?

Share the timestamp, redacted parameters, status, headers, and body. Remove the access key and any target URL details that should remain private.