Rate limits
Understand API rate limits and quotas
Rate limits
AllScreenshots applies rate limits to ensure fair usage and platform stability. This page explains how limits work and how to handle them.
How rate limiting works
Rate limits are applied per API key and measured in requests per minute (RPM). When you exceed the limit, the API returns a 429 Too Many Requests response.
Plan limits
| Plan | Requests per minute | Monthly quota |
|---|---|---|
| Free | 10 RPM | 100 screenshots |
| Starter | 60 RPM | 1,000 screenshots |
| Pro | 120 RPM | 10,000 screenshots |
| Enterprise | Custom | Custom |
Rate limit headers
Every response includes headers showing your current rate limit status:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1704067200| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed per minute |
X-RateLimit-Remaining | Requests remaining in current window |
X-RateLimit-Reset | Unix timestamp when the limit resets |
Handling rate limits
When you hit the rate limit, you'll receive:
HTTP/1.1 429 Too Many Requests
Retry-After: 30
{
"error": "rate_limit_exceeded",
"message": "Rate limit exceeded. Please retry after 30 seconds."
}Retry with exponential backoff
Implement exponential backoff to handle rate limits gracefully:
async function captureWithRetry(url, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch('https://api.allscreenshots.com/v1/screenshots', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ url }),
});
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || Math.pow(2, attempt);
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
continue;
}
return response;
}
throw new Error('Max retries exceeded');
}Best practices
Use bulk endpoints
Instead of making 100 individual requests, use the bulk endpoint to capture multiple URLs in one request:
{
"urls": [
{ "url": "https://example1.com" },
{ "url": "https://example2.com" },
{ "url": "https://example3.com" }
]
}Use async processing
For large workloads, use async jobs with webhooks instead of waiting synchronously:
{
"url": "https://example.com",
"webhookUrl": "https://your-server.com/webhook"
}Cache results
Store screenshots locally and reuse them when possible:
const cacheKey = `screenshot:${url}:${JSON.stringify(options)}`;
const cached = await cache.get(cacheKey);
if (cached) {
return cached;
}
const screenshot = await captureScreenshot(url, options);
await cache.set(cacheKey, screenshot, { ttl: 3600 });
return screenshot;Need higher limits? Contact us about Enterprise plans with custom rate limits and dedicated capacity.
Monthly quotas
In addition to rate limits, your plan has a monthly screenshot quota. When you reach your quota:
- Requests return
402 Payment Required - You can upgrade your plan to continue
- Quotas reset at the start of each billing period
Track your usage in the dashboard under Usage.