API Rate Limiting Issues | Blue Frog Docs

API Rate Limiting Issues

Understanding and fixing API rate limiting and throttling problems

API Rate Limiting Issues

What This Means

Rate limiting is a mechanism that restricts the number of API requests a client can make within a given time period. Rate limiting issues occur when:

  • Applications exceed API quota limits
  • Requests are throttled or rejected (HTTP 429 errors)
  • Users experience degraded functionality
  • Data synchronization fails due to rate limits
  • Batch operations trigger rate limit protection
  • Inefficient API usage exhausts available quota

Common scenarios include third-party API integrations, analytics data collection, social media APIs, payment processors, and cloud service APIs.

How to Diagnose

Check Response Headers

# Inspect rate limit headers
curl -I https://api.example.com/v1/resource

# Common rate limit headers:
# X-RateLimit-Limit: 1000
# X-RateLimit-Remaining: 500
# X-RateLimit-Reset: 1640000000
# Retry-After: 3600

Monitor HTTP Status Codes

  • 429 Too Many Requests - Rate limit exceeded
  • 503 Service Unavailable - Temporary throttling
  • Check response body for rate limit details

Logging and Monitoring

// Log rate limit information
fetch('https://api.example.com/v1/resource')
  .then(response => {
    console.log('Rate Limit:', response.headers.get('X-RateLimit-Limit'));
    console.log('Remaining:', response.headers.get('X-RateLimit-Remaining'));
    console.log('Reset:', response.headers.get('X-RateLimit-Reset'));

    if (response.status === 429) {
      const retryAfter = response.headers.get('Retry-After');
      console.error('Rate limited. Retry after:', retryAfter, 'seconds');
    }
  });

Common Indicators

  • Frequent 429 errors in logs
  • Increasing API failure rates during peak usage
  • Delayed or failed background jobs
  • User-reported "service unavailable" errors

General Fixes

  1. Implement exponential backoff - Retry with increasing delays

    async function fetchWithRetry(url, maxRetries = 3) {
      for (let i = 0; i < maxRetries; i++) {
        const response = await fetch(url);
    
        if (response.status === 429) {
          const retryAfter = response.headers.get('Retry-After') || Math.pow(2, i);
          await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
          continue;
        }
    
        return response;
      }
      throw new Error('Max retries exceeded');
    }
    
  2. Use request queuing - Control concurrent requests

    class RateLimiter {
      constructor(maxRequests, timeWindow) {
        this.maxRequests = maxRequests;
        this.timeWindow = timeWindow;
        this.queue = [];
        this.timestamps = [];
      }
    
      async throttle(fn) {
        while (this.timestamps.length >= this.maxRequests) {
          const oldestTimestamp = this.timestamps[0];
          const waitTime = this.timeWindow - (Date.now() - oldestTimestamp);
          if (waitTime > 0) await new Promise(r => setTimeout(r, waitTime));
          this.timestamps.shift();
        }
    
        this.timestamps.push(Date.now());
        return fn();
      }
    }
    
  3. Cache API responses - Reduce redundant requests

    const cache = new Map();
    
    async function fetchWithCache(url, ttl = 60000) {
      if (cache.has(url)) {
        const { data, timestamp } = cache.get(url);
        if (Date.now() - timestamp < ttl) return data;
      }
    
      const response = await fetch(url);
      const data = await response.json();
      cache.set(url, { data, timestamp: Date.now() });
      return data;
    }
    
  4. Batch API requests - Combine multiple requests when possible

    // Instead of multiple individual requests
    // GET /api/user/1, GET /api/user/2, GET /api/user/3
    
    // Use batch endpoint
    // POST /api/users/batch { ids: [1, 2, 3] }
    
  5. Monitor rate limit headers - Proactively slow down before hitting limits

    function checkRateLimit(response) {
      const remaining = parseInt(response.headers.get('X-RateLimit-Remaining'));
      const limit = parseInt(response.headers.get('X-RateLimit-Limit'));
    
      if (remaining < limit * 0.1) {
        console.warn('Approaching rate limit. Consider slowing down.');
      }
    }
    
  6. Use webhooks instead of polling - Reduce API calls by receiving push notifications

  7. Implement request deduplication - Prevent duplicate concurrent requests

    const pendingRequests = new Map();
    
    async function dedupedFetch(url) {
      if (pendingRequests.has(url)) {
        return pendingRequests.get(url);
      }
    
      const promise = fetch(url).finally(() => pendingRequests.delete(url));
      pendingRequests.set(url, promise);
      return promise;
    }
    
  8. Upgrade API tier - Consider higher-tier plans for increased limits

  9. Distribute requests - Spread requests over time instead of bursts

Platform-Specific Guides

Platform Guide
Stripe API Rate Limits
GitHub API Rate Limiting
Twitter API Rate Limits
Google APIs Usage Limits
AWS API Gateway Throttling

Further Reading

// SYS.FOOTER