ScreenshotNeo

BlogHow-to

Why Does a Screenshot API Return a 400 Error for a Valid URL?

A URL can open in your browser and still fail a screenshot API’s request checks. Use this checklist to find whether the problem is encoding, options, or destination policy.

By the ScreenshotNeo team4 October 20268 min read

A screenshot API can return HTTP 400 even when the URL opens normally in your browser because it validates the entire capture request, not just whether the page exists. The cause may be a malformed request, a missing or unsupported option, incorrectly encoded characters, or a destination blocked by that provider’s URL policy. Start with the response body and the provider’s error documentation; the status alone does not identify the cause.

“Valid URL” can mean three different things: syntactically well-formed, reachable in your browser, and permitted by the screenshot service. Passing one check does not guarantee the others. Provider policies and error codes differ, so treat examples below as diagnostic patterns rather than a universal API contract.

1. Capture the full error before changing the request

Record the HTTP method, endpoint, status, response content type, response body, and any provider request ID. Error bodies may include a stable code, message, or field-level details that identify the rejected parameter. Redact API keys, authorization headers, cookies, and sensitive URL query values before sharing logs or contacting support.

Use the provider’s own error taxonomy. For example, some services document invalid_request responses with field errors, while others have separate URL validation codes. Those names and status mappings are provider-specific. [Screenshot API error documentation] [ScreenshotEngine documentation]

2. Check the request contract, not only the URL

Compare the exact request with the current documentation for the endpoint and method. Verify all of the following:

  • Method and endpoint: Use the documented HTTP method and exact path. A correct URL sent to the wrong endpoint can still be rejected.
  • Required fields: Include every required field, with the exact documented spelling and casing.
  • Placement: Put each field in the documented location: query string, JSON body, or form body. Do not assume options can be moved between them.
  • Types and syntax: Check that JSON is valid and values have the expected types. A number supplied as an unsupported string, for example, may fail validation.
  • Option values: Confirm output format, viewport, selector, proxy, geolocation, and other options are supported by that endpoint and plan where applicable.
  • Headers: Send the documented content type and authentication header or parameter. Authentication failures often have their own status, but the provider’s documentation determines the exact behavior.

Several screenshot services document independent validation for parameters such as format, proxy, geolocation, and custom CSS or JavaScript. A valid url field does not make the rest of the request valid. [ScreenshotAPI.net parameter documentation] [Screenshot Studio documentation]

3. Check URL encoding and destination policy

Encode query values correctly

Special characters in a URL’s query component must survive transport as part of the URL value. If you construct a request by concatenating strings, characters such as &, #, spaces, and non-ASCII characters may be interpreted as part of the API request rather than the target address. Use a query-parameter encoder or the HTTP client’s parameter support instead of hand-building the encoded string.

Cloudflare Support identifies improperly URL-encoded special characters as a cause of HTTP 400 responses. This applies to request transport generally; it does not mean every 400 from a screenshot API is an encoding issue. [Cloudflare: Error 400]

Confirm the address is allowed by the service

Send an absolute http:// or https:// URL in the expected field. A service may reject unsupported schemes, malformed addresses, or destinations that resolve to localhost, private networks, or reserved addresses. Such restrictions are provider-specific security rules intended to control what the service can fetch. Do not try to evade a destination rejection; use a publicly reachable target that you are authorized to capture, or ask the provider about its policy.

For instance, some providers explicitly document HTTP(S)-only URLs and restrictions on private or reserved destinations. That policy should not be assumed for every API. [Screenshot API URL rules] [ScreenshotEngine URL validation]

4. Reduce the request to a minimal reproduction

  1. Make a request to the documented endpoint using a simple public HTTPS page and only required fields.
  2. If it succeeds, add your original URL while keeping the request otherwise minimal.
  3. If that succeeds, restore optional parameters one at a time until the 400 returns.
  4. Check the response body again and compare the failing field against the provider’s allowed values and types.
  5. If the minimal public request still fails, verify credentials, endpoint, method, and request encoding, then contact provider support with redacted diagnostics and the request ID.

This sequence separates request construction problems from URL-specific policy checks and option validation without guessing from the status code.

5. Distinguish 400 from other failures

A 400 commonly indicates that the service rejected the request, but status meanings vary. Do not label every screenshot failure “bad URL.” Check the provider’s documentation for the exact code and response body.

Response class What to inspect
400 Malformed request, missing or invalid field, unsupported option, URL syntax, encoding, or destination policy.
401 or 403 Credential validity, permissions, account restrictions, or access policy.
429 Rate limits, quota, or retry guidance from the provider.
5xx, 502, or 503 Rendering or upstream failures, provider availability, or temporary service problems. Check whether the provider distinguishes these from request errors.

This is a troubleshooting guide, not a universal status-code mapping. Some providers use distinct codes for render failures or selector errors, and their documentation is authoritative. [Screenshot API errors] [ScreenshotOne error guidance]

6. Example: encode the target URL safely

The examples below show the general request-construction principle using a fictional endpoint and parameter names. Replace them with the exact method, endpoint, authentication mechanism, and fields documented by your screenshot provider. The target includes its own query parameters to demonstrate why encoding matters.

cURL

curl --get 'https://api.example.com/v1/screenshot' \
  --data-urlencode 'url=https://example.org/search?q=red shoes&sort=price' \
  --data-urlencode 'format=png' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --output screenshot.png

Python

import requests

endpoint = "https://api.example.com/v1/screenshot"
params = {
    "url": "https://example.org/search?q=red shoes&sort=price",
    "format": "png",
}
headers = {"Authorization": "Bearer YOUR_API_KEY"}

response = requests.get(endpoint, params=params, headers=headers, timeout=90)
if not response.ok:
    print("Status:", response.status_code)
    print("Content-Type:", response.headers.get("content-type"))
    print("Body:", response.text)
    response.raise_for_status()

with open("screenshot.png", "wb") as output:
    output.write(response.content)

Node.js

const endpoint = new URL('https://api.example.com/v1/screenshot');
endpoint.searchParams.set(
  'url',
  'https://example.org/search?q=red shoes&sort=price'
);
endpoint.searchParams.set('format', 'png');

const res = await fetch(endpoint, {
  headers: { Authorization: 'Bearer YOUR_API_KEY' },
});

if (!res.ok) {
  console.error('Status:', res.status);
  console.error('Content-Type:', res.headers.get('content-type'));
  console.error('Body:', await res.text());
  throw new Error('Screenshot request failed');
}

const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('screenshot.png', image));

These examples are templates for safe parameter encoding and error inspection, not runnable against a real provider as written: api.example.com is a placeholder. Use the provider’s actual schema and documented response format.

7. Common 400 errors and fixes

Symptom Likely cause What to do
“Missing parameter” or field error A required field is absent, misspelled, or placed in the wrong part of the request. Match field name, casing, placement, and required status to the endpoint documentation.
“Invalid JSON” or body parse error Malformed JSON, wrong content type, or an unexpected body format. Validate the serialized body and send the documented content type.
“Invalid URL” Relative address, unsupported scheme, malformed URL, or provider destination policy. Use an absolute HTTP(S) URL, then check whether its resolved destination is allowed.
Request works without query parameters but fails with them Special characters were not encoded or the URL was manually concatenated. Use --data-urlencode, a parameter object, or URLSearchParams.
“Unsupported format” or option error An option value is invalid or unavailable on that endpoint. Start with the smallest request and restore options individually using documented values.
Request gets 401, 403, or 429 instead Authentication, access, throttling, or quota issue rather than necessarily an invalid target URL. Follow the provider’s guidance for that status; do not keep changing the URL without evidence.
5xx or render failure The request may have passed validation, but navigation or an upstream service failed. Inspect the provider’s render-failure details and retry policy; distinguish this from a 400.

8. Reliability, performance, and cost considerations

  • Reliability: Preserve status, response body, and request ID in application diagnostics, while redacting secrets. Retry only errors the provider documents as transient; repeatedly retrying a deterministic validation error will not fix it.
  • Performance: A 400 is generally returned during request validation, before a successful page capture. For slower render or upstream failures, follow the provider’s timeout and retry guidance rather than treating them as URL syntax problems.
  • Cost: Billing rules vary by provider. Check whether failed validation, render failures, or cached results count toward usage before designing retries or bulk capture. Do not infer billing from HTTP status unless the provider documents it.
  • Security: A destination block may protect the service from fetching private network resources. Do not attempt to bypass that policy. Keep keys and private query values out of logs and support tickets.

9. Or skip the browser setup

If you want to focus on capturing pages instead of maintaining browser infrastructure, ScreenshotNeo is a website screenshot API and MCP server. Its one-call endpoint returns a PNG, JPEG, WebP, or PDF, and the API documentation lists the request options and response behavior.

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}`);

ScreenshotNeo accepts cookie and consent banners like a visitor, then removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server gives AI agents tools for screenshots, page information, and PDF capture. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.

Create a free ScreenshotNeo account for 1,000 screenshots a month, with no card required.

FAQ

Can a URL be valid in a browser but invalid to the API?

Yes. The API also checks how the request is formed and whether its destination policy permits the target.

Should I encode the entire URL before passing it to my HTTP client?

Usually, pass the raw target URL as a parameter value and let the client encode the outer API request. Pre-encoding can cause double encoding. Follow the client and provider documentation.

Does changing screenshot providers necessarily fix a 400?

No. First identify the rejected field or policy from the response. Providers have different schemas and destination rules, so switching is only useful if the other provider’s documented contract fits your use case.

What should I include in a support request?

Include method, endpoint, redacted request fields, status, response body, approximate time, and request ID if present. Never include a secret key or sensitive cookies.