PagePry

Errors

Error codes, response format, and how to handle errors.

All error responses follow a consistent format:

{
  "success": false,
  "error": "Human-readable error message"
}

Error codes

HTTP StatusCodeDescription
400VALIDATION_ERRORInvalid request parameters. Check the error field for details on which parameters failed validation.
401AUTHENTICATION_ERRORMissing or invalid API key. Ensure you're passing a valid key in the x-api-key header.
403FORBIDDENYour API key doesn't have access to this resource.
408TIMEOUT_ERRORThe page didn't finish loading within the configured timeoutMs. Try increasing the timeout or using a different waitFor strategy.
429RATE_LIMIT_ERRORYou've exceeded your plan's rate limit. Wait and retry, or upgrade your plan for higher limits.
429USAGE_LIMIT_ERRORYour organization has run out of credits for this billing period. Purchase more credits or wait for the next billing cycle.
500BROWSER_ERRORAn internal browser error occurred. This is usually transient — retry the request.
502TARGET_SITE_ERRORThe target website is unreachable, returned an error, or blocked the request. Consider using a proxy.
502PROXY_ERRORThe proxy connection failed. This is usually transient — retry the request.

Handling errors

Retryable errors

These errors are typically transient and safe to retry with exponential backoff:

  • 408 TIMEOUT_ERROR — try increasing timeoutMs
  • 429 RATE_LIMIT_ERROR — wait and retry (check Retry-After header if present)
  • 500 BROWSER_ERROR — retry after a short delay
  • 502 PROXY_ERROR — retry after a short delay

Non-retryable errors

These errors require fixing the request before retrying:

  • 400 VALIDATION_ERROR — fix the request parameters
  • 401 AUTHENTICATION_ERROR — check your API key
  • 403 FORBIDDEN — check your API key permissions
  • 429 USAGE_LIMIT_ERROR — add credits or wait for the next billing cycle
  • 502 TARGET_SITE_ERROR — the target site may be down, or you may need to use a proxy

Example retry logic

async function scrapeWithRetry(url, maxRetries = 3) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const response = await fetch('https://api.pagepry.com/v1/scrape', {
      method: 'POST',
      headers: {
        'x-api-key': process.env.PAGEPRY_API_KEY,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ url }),
    });

    if (response.ok) return response.json();

    const data = await response.json();
    const retryable = [408, 500, 502].includes(response.status)
      || (response.status === 429 && data.code === 'RATE_LIMIT_ERROR');

    if (!retryable || attempt === maxRetries) throw new Error(data.error);

    const delay = Math.min(1000 * 2 ** attempt, 30000);
    await new Promise(resolve => setTimeout(resolve, delay));
  }
}