API Reference

Rate Limits

API endpoints are rate-limited to ensure fair usage and system stability. Limits vary by subscription plan and endpoint type.

Plan-Based Rate Limits

PlanRequests per 10 secondsRequests per minute
Free50300
Hobby100600
Pro2001,200
Scale5003,000

Endpoint-Specific Limits

Some endpoints have additional restrictions regardless of plan:

Endpoint TypeLimitNotes
Public endpoints100/minUnauthenticated requests
Authentication30/minLogin, token refresh
Custom SQL queries30/minHigher computational cost
Batch operationsVariesBased on batch size

Rate Limit Headers

Every response includes rate limit information:

http
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 195
X-RateLimit-Reset: 1704067210
HeaderDescription
X-RateLimit-LimitMaximum requests allowed in the window
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetUnix timestamp when the limit resets

Rate Limit Exceeded Response

When you exceed the rate limit, you'll receive a 429 response:

json
{
"success": false,
"error": "Rate limit exceeded. Please try again later.",
"code": "RATE_LIMIT_EXCEEDED",
"limit": 200,
"remaining": 0,
"reset": "2024-01-01T12:00:10.000Z",
"retryAfter": 8
}

The retryAfter field indicates seconds until you can retry.

Best Practices

1. Use Batch Queries

Instead of multiple individual requests, combine queries:

json
// Instead of 3 separate requests:
// POST /v1/query { parameters: ["summary"] }
// POST /v1/query { parameters: ["pages"] }
// POST /v1/query { parameters: ["traffic"] }

// Use one batch request:
POST /v1/query
{
"parameters": ["summary", "pages", "traffic"],
"startDate": "2024-01-01",
"endDate": "2024-01-31"
}

2. Implement Exponential Backoff

When rate limited, wait progressively longer:

typescript
async function fetchWithRetry(url: string, options: RequestInit, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
  const response = await fetch(url, options);
  
  if (response.status === 429) {
    const retryAfter = response.headers.get('X-RateLimit-Reset');
    const waitTime = retryAfter 
      ? (parseInt(retryAfter) * 1000) - Date.now()
      : Math.pow(2, attempt) * 1000;
    
    await new Promise(resolve => setTimeout(resolve, Math.max(waitTime, 1000)));
    continue;
  }
  
  return response;
}
throw new Error('Max retries exceeded');
}

3. Cache Responses

Cache analytics data that doesn't change frequently:

typescript
// Cache daily summaries - they won't change after the day ends
const cacheKey = `summary-${websiteId}-${date}`;
const cached = await cache.get(cacheKey);

if (cached) {
return cached;
}

const data = await fetchAnalytics(websiteId, date);

// Cache for 1 hour for recent data, longer for historical
const ttl = isToday(date) ? 3600 : 86400;
await cache.set(cacheKey, data, ttl);

return data;

4. Monitor Rate Limit Headers

Track remaining requests proactively:

typescript
const response = await fetch(url, options);
const remaining = parseInt(response.headers.get('X-RateLimit-Remaining') || '0');

if (remaining < 10) {
console.warn(`Rate limit warning: ${remaining} requests remaining`);
// Slow down or queue requests
}

Increasing Your Limits

Need higher rate limits? Upgrade your plan or contact us for custom enterprise limits.

Enterprise customers can request custom rate limits based on their specific use case.

How is this guide?