Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.screenshotly.dev/llms.txt

Use this file to discover all available pages before exploring further.

Screenshotly enforces rate limits to ensure fair usage and service reliability.

Limits by plan

PlanMonthly screenshotsStorageRate limitPrice
Free100500 MB5 req/minFree
Starter5,0005 GB20 req/min$29/mo
Pro25,00015 GB60 req/min$79/mo
Business75,00050 GB120 req/min$199/mo
Rate limits are applied per API key within a 60-second sliding window. Check your current usage in the dashboard.

Rate limit headers

Every API response includes headers to help you track your usage:
HeaderDescription
X-RateLimit-LimitMaximum requests per minute for your plan
X-RateLimit-RemainingRemaining requests in the current window
X-RateLimit-ResetUnix timestamp when the rate limit window resets
When you hit the rate limit, a Retry-After header is also included indicating how many seconds to wait.

429 Too Many Requests

When you exceed your per-minute rate limit, the API returns a 429 status code:
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Too many requests. Please try again later."
  }
}

402 Usage Limit Exceeded

When you exceed your monthly screenshot quota, the API returns a 402 status code:
{
  "error": {
    "code": "usage_limit_exceeded",
    "message": "Monthly screenshot limit reached. Please upgrade your subscription."
  }
}

Checking your usage

Use the usage endpoint to check your remaining credits programmatically:
curl https://api.screenshotly.dev/v1/screenshots/usage \
  -H "X-API-Key: $SCREENSHOTLY_API_KEY"
When using response_type: "json" for captures, the response includes a remaining_credits field.

Handling rate limits

Exponential backoff

When you receive a 429 response, wait before retrying:
async function captureWithBackoff(url, options) {
  const maxRetries = 5;

  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;
    if (response.status !== 429) throw new Error(`HTTP ${response.status}`);

    const retryAfter = response.headers.get('Retry-After');
    const delay = retryAfter ? parseInt(retryAfter) * 1000 : Math.pow(2, attempt) * 1000;
    console.log(`Rate limited. Retrying in ${delay}ms...`);
    await new Promise(resolve => setTimeout(resolve, delay));
  }

  throw new Error('Rate limit retry attempts exhausted');
}

Best practices

  • Monitor usage — check the X-RateLimit-Remaining header or the usage endpoint before large operations
  • Stagger requests — spread requests over time instead of sending them all at once
  • Use batch processing — the batch endpoint processes up to 50 URLs per request
  • Respect Retry-After — use the header value for optimal retry timing
  • Upgrade your plan — if you consistently hit limits, consider upgrading at pricing
  • Cache results — store screenshot URLs and reuse them instead of recapturing the same pages