Skip to main content
The Screenshotly API uses standard HTTP status codes to indicate success or failure.

Status code overview

RangeMeaning
2xxThe request succeeded
4xxThe request failed due to a client error
5xxThe request failed due to a server error

Error response format

All error responses return a JSON body with an error object containing code and message fields:
{
  "error": {
    "code": "invalid_options",
    "message": "Validation failed."
  }
}
Some errors include a details field with additional context:
{
  "error": {
    "code": "invalid_options",
    "message": "Validation failed.",
    "details": {
      "url": "\"url\" is required"
    }
  }
}

Error codes

StatusCodeDescription
401missing_api_keyNo API key provided. Pass it via the X-API-Key header or api_key query parameter.
401invalid_api_keyThe provided API key is invalid or has been revoked.
401unauthorizedAuthentication required. Provide a valid API key.
402usage_limit_exceededMonthly screenshot limit reached. Upgrade your subscription at the dashboard.
403forbiddenYou do not have permission to access this resource.
404not_foundThe requested resource (e.g., screenshot ID) was not found.
422invalid_optionsValidation failed. Check the details field for specific parameter errors.
422invalid_urlThe provided URL is not valid. Ensure it includes a protocol (e.g., https://).
422selector_not_foundThe specified CSS selector was not found on the page. Only returned when error_on_selector_not_found is true.
429rate_limit_exceededToo many requests per minute. See rate limits.
500render_failedScreenshot rendering failed. The target page may have caused an error.
500internal_errorAn unexpected server error occurred. Retry the request. If it persists, contact support.
502host_errorCould not reach the target URL. The site may be down or blocking requests.
503service_unavailableThe screenshot service is starting up. Retry in a few seconds.
504navigation_timeoutPage navigation timed out. Try increasing the navigation_timeout or timeout options.

Handling errors

Python

import requests

response = requests.post(
    'https://api.screenshotly.dev/v1/capture',
    headers={'X-API-Key': API_KEY, 'Content-Type': 'application/json'},
    json={'url': 'https://example.com', 'options': {'response_type': 'json'}}
)

if response.status_code == 401:
    print('Check your API key')
elif response.status_code == 402:
    print('Monthly limit reached — upgrade your plan')
elif response.status_code == 429:
    print('Rate limited — retry after a delay')
elif response.status_code >= 400:
    error = response.json()['error']
    print(f"Error [{error['code']}]: {error['message']}")

JavaScript

const response = await fetch('https://api.screenshotly.dev/v1/capture', {
  method: 'POST',
  headers: {
    'X-API-Key': process.env.SCREENSHOTLY_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://example.com',
    options: { response_type: 'json' },
  }),
});

if (!response.ok) {
  const { error } = await response.json();
  console.error(`Error [${error.code}]: ${error.message}`);

  if (error.details) {
    console.error('Details:', error.details);
  }
}

Retry strategy

For transient errors (429, 5xx), implement exponential backoff:
async function captureWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const response = await fetch('https://api.screenshotly.dev/v1/capture', {
      method: 'POST',
      headers: {
        'X-API-Key': process.env.SCREENSHOTLY_API_KEY,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ url, options }),
    });

    if (response.ok) return response;

    // Don't retry client errors (except 429)
    if (response.status >= 400 && response.status < 500 && response.status !== 429) {
      const { error } = await response.json();
      throw new Error(`${error.code}: ${error.message}`);
    }

    // Wait before retrying: 1s, 2s, 4s
    const delay = Math.pow(2, attempt) * 1000;
    await new Promise(resolve => setTimeout(resolve, delay));
  }

  throw new Error('Max retries exceeded');
}