Errors

In this guide, we will talk about what happens when something goes wrong while you work with the Screenshot API. Understanding error responses will help you debug issues and handle failures gracefully in your applications.

You can tell if your request was successful by checking the status code when receiving an API response. If a response comes back unsuccessful, you can use the error type and error message to figure out what has gone wrong and implement appropriate error handling.


Status codes

Here are the different categories of status codes returned by the Screenshot API:

  • Name
    200
    Description

    OK - Cached screenshot returned immediately

  • Name
    202
    Description

    Accepted - Screenshot job created successfully, use job ID to check status

  • Name
    400
    Description

    Bad Request - Invalid request parameters or malformed JSON

  • Name
    401
    Description

    Unauthorized - Missing or invalid API key

  • Name
    403
    Description

    Forbidden - API key lacks required permissions

  • Name
    404
    Description

    Not Found - Job ID not found or resource doesn't exist

  • Name
    500
    Description

    Internal Server Error - Server error (rare)


Authentication Errors

Authentication errors occur when there are issues with your API key. These are the most common errors you'll encounter.

  • Name
    ApiKeyRequired
    Description

    No API key was provided in the request headers or query parameters.

  • Name
    InvalidApiKey
    Description

    The provided API key is not valid or has been revoked.

  • Name
    InsufficientPermissions
    Description

    The API key doesn't have the required permissions for this operation.

Missing API key (401)

{
  "status": 401,
  "error": "ApiKeyRequired",
  "message": "API key is required"
}

Invalid API key (401)

{
  "status": 401,
  "error": "InvalidApiKey",
  "message": "Invalid API key"
}

Insufficient permissions (403)

{
  "status": 403,
  "error": "InsufficientPermissions",
  "message": "API key does not have the required permissions"
}

Validation Errors

Validation errors occur when your request parameters don't meet the API requirements. These errors include detailed information about what went wrong.

  • Name
    ValidationError
    Description

    One or more request parameters are invalid or missing.

  • Name
    InvalidUrl
    Description

    The provided URL is not a valid HTTP or HTTPS URL.

  • Name
    ParameterOutOfRange
    Description

    A numeric parameter is outside the allowed range.

Invalid URL (400)

{
  "status": 400,
  "error": "ValidationError",
  "message": "URL must be a valid HTTP or HTTPS URL",
  "details": {
    "field": "url",
    "value": "not-a-url",
    "constraint": "Must be valid URL"
  }
}

Missing viewport (400)

{
  "status": 400,
  "error": "ValidationError", 
  "message": "Viewport dimensions are required",
  "details": {
    "field": "viewport",
    "constraint": "Required field"
  }
}

Invalid quality (400)

{
  "status": 400,
  "error": "ValidationError",
  "message": "Quality must be at least 1",
  "details": {
    "field": "quality",
    "value": 0,
    "constraint": "minimum: 1"
  }
}

Job Errors

Job errors occur during screenshot processing. These are returned when checking job status.

  • Name
    JobNotFound
    Description

    The specified job ID doesn't exist or has expired.

  • Name
    NavigationFailed
    Description

    Failed to navigate to the target URL.

  • Name
    TimeoutError
    Description

    Page load exceeded the specified timeout.

  • Name
    CaptureError
    Description

    Error occurred while capturing the screenshot.

Job not found (404)

{
  "status": 404,
  "error": "JobNotFound",
  "message": "Job with ID abc123 not found"
}

Failed job response

{
  "jobId": "550e8400-e29b-41d4-a716-446655440000",
  "status": "failed",
  "createdAt": "2023-12-07T10:30:00Z",
  "failedAt": "2023-12-07T10:30:10Z",
  "error": {
    "code": "NAVIGATION_FAILED",
    "message": "Failed to navigate to URL",
    "details": "Timeout waiting for page load"
  }
}

Timeout error

{
  "jobId": "550e8400-e29b-41d4-a716-446655440000",
  "status": "failed",
  "error": {
    "code": "TIMEOUT_ERROR",
    "message": "Page load timeout exceeded",
    "details": "Page took longer than 30000ms to load"
  }
}

Error Handling Best Practices

1. Retry Logic

Implement exponential backoff for temporary failures:

async function captureScreenshotWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch('/screenshot', {
        method: 'POST',
        headers: {
          'x-api-key': 'your_api_key',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ url, ...options })
      });

      if (response.ok) {
        return await response.json();
      }

      if (response.status === 401 || response.status === 403) {
        // Don't retry auth errors
        throw new Error('Authentication failed');
      }

      if (attempt === maxRetries) {
        throw new Error(`Failed after ${maxRetries} attempts`);
      }

      // Exponential backoff
      await new Promise(resolve => 
        setTimeout(resolve, Math.pow(2, attempt) * 1000)
      );

    } catch (error) {
      if (attempt === maxRetries) throw error;
    }
  }
}

2. Job Status Polling

Handle different job states appropriately:

async function pollJobStatus(jobId, maxWaitTime = 60000) {
  const startTime = Date.now();
  
  while (Date.now() - startTime < maxWaitTime) {
    const response = await fetch(`/screenshot/status/${jobId}`, {
      headers: { 'x-api-key': 'your_api_key' }
    });
    
    const status = await response.json();
    
    switch (status.status) {
      case 'completed':
        return status;
      
      case 'failed':
        throw new Error(`Job failed: ${status.error.message}`);
      
      case 'pending':
      case 'processing':
        await new Promise(resolve => setTimeout(resolve, 2000));
        break;
      
      default:
        throw new Error(`Unknown status: ${status.status}`);
    }
  }
  
  throw new Error('Job polling timeout');
}

3. Parameter Validation

Validate parameters before sending requests:

function validateScreenshotRequest(params) {
  const errors = [];
  
  if (!params.url || !isValidUrl(params.url)) {
    errors.push('Valid URL is required');
  }
  
  if (!params.viewport || !params.viewport.width || !params.viewport.height) {
    errors.push('Viewport width and height are required');
  }
  
  if (params.quality && (params.quality < 1 || params.quality > 100)) {
    errors.push('Quality must be between 1 and 100');
  }
  
  if (errors.length > 0) {
    throw new Error(`Validation failed: ${errors.join(', ')}`);
  }
}

function isValidUrl(string) {
  try {
    const url = new URL(string);
    return url.protocol === 'http:' || url.protocol === 'https:';
  } catch {
    return false;
  }
}

Common Error Scenarios

URL Not Reachable

{
  "jobId": "550e8400-e29b-41d4-a716-446655440000",
  "status": "failed",
  "error": {
    "code": "NAVIGATION_FAILED",
    "message": "Failed to navigate to URL",
    "details": "net::ERR_NAME_NOT_RESOLVED"
  }
}

Solution: Verify the URL is correct and accessible from the internet.

Page Load Timeout

{
  "error": {
    "code": "TIMEOUT_ERROR",
    "message": "Page load timeout exceeded",
    "details": "Page took longer than 30000ms to load"
  }
}

Solution: Increase the timeoutMs parameter or optimize the target page loading speed.

Invalid Device Emulation

{
  "status": 400,
  "error": "ValidationError",
  "message": "deviceEmulation must be one of: iPhone X, iPhone 12, ..."
}

Solution: Use the /screenshot/devices endpoint to get valid device names.

Was this page helpful?