Handle API Rate Limits in n8n Without Breaking Workflows
Handle API Rate Limits in n8n Without Breaking Workflows
β€’ Logic Workflow Team

Handle API Rate Limits in n8n Without Breaking Workflows

#n8n #rate limiting #API #throttling #429 errors #performance

Your n8n workflow processes 100 records flawlessly. Then you run it with 1,000 records and it crashes halfway through with 429 Too Many Requests.

Rate limits exist to protect APIs from abuse, but they don’t care that your workflow was working fine yesterday. This guide shows you how to build n8n workflows that respect rate limits and keep running when others would fail.

Understanding API Rate Limits

Rate limits restrict how many API requests you can make in a given time period. When you exceed the limit, the API returns a 429 Too Many Requests error instead of your data.

Common rate limit structures:

TypeExampleHow It Works
Requests per second10 req/secMax 10 calls every second
Requests per minute60 req/minMax 60 calls per minute (not 1/sec)
Requests per day1,000 req/dayHard daily cap, resets at midnight
Concurrent requests5 simultaneousMax 5 in-flight requests at once
Token-based90,000 tokens/minAI APIs measure by data size, not requests

What a 429 error looks like in n8n:

ERROR: Request failed with status code 429
NodeApiError: The service is receiving too many requests from you
Rate limit exceeded. Please retry after 60 seconds.

Quick Reference: Rate Limit Solutions

ProblemSolutionJump To
Processing too many items at onceSplit In Batches nodeBatching Requests
Requests firing too fastWait node between callsAdding Delays
Occasional 429 errorsHTTP Request retry settingsBuilt-in Retries
Need smart retry logicExponential backoff in Code nodeExponential Backoff
Complex rate limit rulesRate limiter patternRate Limiter Pattern

Using Built-in Retry Settings

Before building complex solutions, try n8n’s built-in retry mechanism in the HTTP Request node.

How to configure:

  1. Open your HTTP Request node
  2. Go to Settings (gear icon)
  3. Find Retry On Fail
  4. Configure:
    • Retry On Fail: Enabled
    • Max Tries: 3-5
    • Wait Between Tries: 1000ms (or higher)
Settings:
β”œβ”€β”€ Retry On Fail: true
β”œβ”€β”€ Max Tries: 3
└── Wait Between Tries (ms): 1000

When built-in retries work:

  • Occasional rate limits from traffic spikes
  • APIs that clear quickly after brief waits
  • Low-volume workflows with infrequent 429s

When you need more:

  • Processing hundreds or thousands of items
  • APIs with strict per-second limits
  • Multiple workflows hitting the same API
  • Need exponential backoff (increasing delays)

For timeout-related issues that often accompany rate limits, see our guide to fixing n8n timeout errors.

Pattern 1: Batch Processing with Split In Batches

The most common rate limit fix: process items in smaller groups with pauses between them.

The workflow structure:

Trigger β†’ Get Data β†’ Split In Batches β†’ Process β†’ Wait β†’ Loop Back
                            ↓
                      (When done) β†’ Continue workflow

Step-by-step setup:

Step 1: Add Split In Batches Node

After your data source, add a Split In Batches node (also called β€œLoop Over Items”):

Node: Split In Batches
β”œβ”€β”€ Batch Size: 10
└── Options: (default)

The batch size depends on your API’s rate limit:

  • 10 req/sec limit: Batch size of 10, then wait 1 second
  • 60 req/min limit: Batch size of 50, then wait 1 minute
  • Concurrent limit of 5: Batch size of 5, process, repeat

Step 2: Add Your Processing Node

Connect the second output of Split In Batches to your HTTP Request or API node:

Split In Batches
β”œβ”€β”€ Output 1: "No items left" (workflow continues)
└── Output 2: "Items in batch" β†’ Your API node

Step 3: Add Wait Node

After your API node, add a Wait node:

Node: Wait
β”œβ”€β”€ Resume: After Time Interval
β”œβ”€β”€ Amount: 1
└── Unit: Seconds

Step 4: Loop Back

Connect the Wait node back to the Split In Batches node input. This creates the loop.

Complete workflow example:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Trigger   │───▸│ Split In Batches │───▸│  HTTP Req   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β–²                     β”‚
                            β”‚                     β–Ό
                   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                   β”‚  Continue when  β”‚    β”‚    Wait     β”‚
                   β”‚   done (out 1)  β”‚    β”‚   1 second  β”‚
                   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                 β”‚
                                                 β–Ό
                                          (loops back)

Calculating Batch Size and Wait Time

Formula:

Batch Size = Rate Limit Γ— Safety Margin
Wait Time = Time Window / (Rate Limit / Batch Size)

Examples:

Rate LimitBatch SizeWait TimeEffective Rate
10/second81 second8/sec (80% of limit)
100/minute8060 seconds80/min (80% of limit)
1000/hour80060 minutes800/hr (80% of limit)

Why 80%? Leave headroom for:

  • Other workflows using the same API
  • Retry attempts
  • Rate limit fluctuations

Pattern 2: Adding Delays Between Requests

For simple workflows processing items one at a time, add a Wait node after each API call.

When to use:

  • Sequential processing (not batched)
  • Low item counts (under 100)
  • Simple rate limits (X per second)

Setup:

Trigger β†’ Loop Over Items β†’ HTTP Request β†’ Wait (200ms) β†’ Loop

Wait node settings:

Node: Wait
β”œβ”€β”€ Resume: After Time Interval
β”œβ”€β”€ Amount: 200
└── Unit: Milliseconds

Calculate your delay:

// For a rate limit of 5 requests per second:
delay = 1000ms / 5 = 200ms per request

// For 60 requests per minute:
delay = 60000ms / 60 = 1000ms per request

// Add 20% safety margin:
safe_delay = delay Γ— 1.2

Pattern 3: Exponential Backoff

When you hit a rate limit, waiting a fixed time isn’t always enough. Exponential backoff increases the wait time with each retry, reducing pressure on the API.

How it works:

  • 1st retry: Wait 1 second
  • 2nd retry: Wait 2 seconds
  • 3rd retry: Wait 4 seconds
  • 4th retry: Wait 8 seconds

Implementation with Code node:

Add this Code node before your HTTP Request:

// Get retry count from previous attempts (or start at 0)
const retryCount = $json.retryCount || 0;
const maxRetries = 5;

// Check if we've exceeded max retries
if (retryCount >= maxRetries) {
  throw new Error(`Failed after ${maxRetries} retries`);
}

// Calculate delay with exponential backoff + jitter
const baseDelay = 1000; // 1 second
const maxDelay = 32000; // 32 seconds cap
const exponentialDelay = Math.min(baseDelay * Math.pow(2, retryCount), maxDelay);

// Add random jitter (Β±20%) to prevent thundering herd
const jitter = exponentialDelay * 0.2 * (Math.random() - 0.5);
const finalDelay = Math.round(exponentialDelay + jitter);

// Wait for the calculated delay
if (retryCount > 0) {
  await new Promise(resolve => setTimeout(resolve, finalDelay));
}

// Pass through data with updated retry count
return {
  json: {
    ...$json,
    retryCount: retryCount,
    nextRetryDelay: finalDelay
  }
};

Handling 429 responses:

After your HTTP Request node, add an IF node to check for rate limits:

IF Node Conditions:
β”œβ”€β”€ Value 1: {{ $json.statusCode }}
β”œβ”€β”€ Operation: Equal
└── Value 2: 429

If true (rate limited):

  1. Increment retry count
  2. Loop back to the exponential backoff Code node

If false (success):

  1. Continue with workflow
  2. Reset retry count for next item

Pattern 4: Rate Limiter with Sliding Window

For complex scenarios with multiple API calls or shared limits, implement a sliding window rate limiter.

Code node implementation:

// Configuration
const RATE_LIMIT = 10; // requests
const TIME_WINDOW = 1000; // milliseconds (1 second)

// Get or initialize the request log from static data
const staticData = $getWorkflowStaticData('global');
staticData.requestLog = staticData.requestLog || [];

// Clean old entries outside the time window
const now = Date.now();
staticData.requestLog = staticData.requestLog.filter(
  timestamp => now - timestamp < TIME_WINDOW
);

// Check if we can make a request
if (staticData.requestLog.length >= RATE_LIMIT) {
  // Calculate wait time until oldest request expires
  const oldestRequest = Math.min(...staticData.requestLog);
  const waitTime = TIME_WINDOW - (now - oldestRequest) + 100; // +100ms buffer

  // Wait before proceeding
  await new Promise(resolve => setTimeout(resolve, waitTime));

  // Clean log again after waiting
  const newNow = Date.now();
  staticData.requestLog = staticData.requestLog.filter(
    timestamp => newNow - timestamp < TIME_WINDOW
  );
}

// Log this request
staticData.requestLog.push(Date.now());

// Continue with the item
return $input.all();

When to use this pattern:

  • Multiple HTTP nodes hitting the same API
  • Shared rate limits across workflows
  • Need precise control over request timing

Service-Specific Rate Limit Settings

Different APIs have different limits. Here’s how to configure n8n for popular services:

OpenAI / GPT APIs

Rate limits (vary by tier):

  • Free tier: 3 RPM (requests per minute), 40,000 TPM (tokens per minute)
  • Tier 1: 60 RPM, 60,000 TPM
  • Tier 2+: Higher limits

Recommended n8n settings:

Split In Batches: 50 items
Wait: 60 seconds

Or for token-heavy requests:

Split In Batches: 10 items
Wait: 30 seconds

Pro tip: OpenAI rate limits are per-model. GPT-4 and GPT-3.5 have separate limits.

Airtable

Rate limits:

  • 5 requests per second per base
  • Batch operations: 10 records per request

Recommended n8n settings:

Split In Batches: 10 records
Wait: 250 milliseconds

Use Airtable’s batch operations when possibleβ€”creating 10 records in one API call counts as 1 request, not 10.

HubSpot

Rate limits:

  • 100 requests per 10 seconds (standard)
  • 150,000 requests per day

Recommended n8n settings:

Split In Batches: 80 items
Wait: 10 seconds

Google APIs (Sheets, Drive, Gmail)

Rate limits:

  • Varies by API and quota
  • Sheets: 300 requests per minute per project
  • Drive: 1,000 requests per 100 seconds

Recommended n8n settings:

Split In Batches: 50 items
Wait: 20 seconds

Slack

Rate limits:

  • Tier 1 methods: 1 request per second
  • Tier 2 methods: 20 requests per minute
  • Tier 3 methods: 50 requests per minute

Recommended n8n settings:

Split In Batches: 1 item (for posting messages)
Wait: 1 second

Notion

Rate limits:

  • 3 requests per second

Recommended n8n settings:

Split In Batches: 3 items
Wait: 1 second

Handling Rate Limit Headers

Many APIs tell you exactly how to handle rate limits in their response headers:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1640000000
Retry-After: 60

Extract and use these headers in a Code node:

const items = $input.all();
const results = [];

for (const item of items) {
  // Check if we have rate limit info from previous request
  const remaining = item.json.rateLimitRemaining;
  const resetTime = item.json.rateLimitReset;

  if (remaining !== undefined && remaining <= 1) {
    // We're at the limit, wait until reset
    const now = Math.floor(Date.now() / 1000);
    const waitSeconds = Math.max(0, resetTime - now) + 1;

    if (waitSeconds > 0) {
      await new Promise(resolve =>
        setTimeout(resolve, waitSeconds * 1000)
      );
    }
  }

  results.push(item);
}

return results;

After your HTTP Request, extract headers:

// In a Code node after HTTP Request
const response = $input.first();

return {
  json: {
    data: response.json,
    rateLimitRemaining: parseInt(
      response.headers['x-ratelimit-remaining'] || '999'
    ),
    rateLimitReset: parseInt(
      response.headers['x-ratelimit-reset'] || '0'
    )
  }
};

Monitoring Rate Limit Errors

Don’t wait for workflows to failβ€”monitor rate limits proactively.

Error Workflow for Rate Limits

Create an error handling workflow:

Error Trigger β†’ IF (contains "429") β†’ Alert (Slack/Email)
                                   β†’ Log to database

IF node condition:

{{ $json.error.message.includes('429') ||
   $json.error.message.includes('rate limit') }}

Track Rate Limit Metrics

Add logging to your rate-limited workflows:

// Before making API calls, log the attempt
const staticData = $getWorkflowStaticData('global');
staticData.apiCalls = (staticData.apiCalls || 0) + 1;
staticData.lastCall = new Date().toISOString();

// After catching a 429
staticData.rateLimitHits = (staticData.rateLimitHits || 0) + 1;
staticData.lastRateLimitHit = new Date().toISOString();

return $input.all();

Common Mistakes to Avoid

Mistake 1: Not Accounting for All API Calls

Your workflow might make more API calls than you realize:

❌ Thinking: "I'm only calling the API once per item"
βœ“ Reality: OAuth refresh, pagination, and retries add extra calls

Fix: Count actual HTTP requests in n8n’s execution log, not just your main API nodes.

Mistake 2: Multiple Workflows Sharing Limits

Two workflows hitting the same API = double the requests against the same limit.

Fix: Use static data to coordinate across workflows, or stagger workflow execution times.

Mistake 3: Ignoring Burst Limits

Some APIs have both sustained limits AND burst limits:

Sustained: 100 requests/minute βœ“
Burst: Max 20 requests in any 5-second window βœ—

Fix: Even with correct per-minute pacing, add small delays between individual requests.

Mistake 4: Retrying Immediately on 429

// ❌ Bad: Immediate retry
if (response.status === 429) {
  return makeRequest(); // Just hammers the API
}

// βœ“ Good: Wait before retry
if (response.status === 429) {
  const retryAfter = response.headers['retry-after'] || 60;
  await sleep(retryAfter * 1000);
  return makeRequest();
}

Testing Your Rate Limit Handling

Before processing production data, test your rate limit handling:

Test 1: Simulate Rate Limits

Use a Code node to randomly return 429 errors:

// Simulate 20% rate limit hits
if (Math.random() < 0.2) {
  throw new Error('429 Too Many Requests (simulated)');
}

return $input.all();

Test 2: Time Your Batch Processing

Add timing to verify your pacing:

const startTime = Date.now();
const items = $input.all();

// After processing...
const elapsed = Date.now() - startTime;
const itemsPerSecond = items.length / (elapsed / 1000);

console.log(`Processed ${items.length} items in ${elapsed}ms`);
console.log(`Rate: ${itemsPerSecond.toFixed(2)} items/second`);

return items;

Test 3: Verify Backoff Behavior

Check that delays increase properly on retries:

const retryCount = $json.retryCount || 0;
const expectedDelay = 1000 * Math.pow(2, retryCount);

console.log(`Retry ${retryCount}: Expected delay ${expectedDelay}ms`);

Need Help?

Rate limit handling adds complexity to workflows. If you’re dealing with:

  • High-volume data processing
  • Multiple APIs with different limits
  • Production workflows that can’t afford failures

Our workflow audit service can identify rate limit risks, and our development services build production-ready workflows with proper rate limiting from the start.

Frequently Asked Questions

What does a 429 error mean in n8n?

A 429 error means β€œToo Many Requests”—you’ve exceeded the API’s rate limit. The API is telling n8n to slow down. This isn’t a bug in your workflow; it’s the API protecting itself from overload. The fix is to reduce your request frequency using batching, delays, or exponential backoff. Most APIs include a Retry-After header telling you how long to wait.

How do I know what rate limit an API has?

Check the API’s documentation for rate limit informationβ€”it’s usually in a section called β€œRate Limits,” β€œThrottling,” or β€œAPI Quotas.” If undocumented, look at response headers like X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset. You can also test empirically: send requests until you get a 429, then calculate the limit from the timing.

What’s the difference between Split In Batches and Loop Over Items?

They’re the same nodeβ€”β€œLoop Over Items” is the display name, β€œSplit In Batches” is the technical name (n8n-nodes-base.splitInBatches). The node divides your items into smaller groups (batches) and processes them one batch at a time. Setting batch size to 1 processes items individually; setting it higher processes multiple items per loop iteration.

Should I use Wait node or setTimeout in Code node?

Use the Wait node for simple, fixed delaysβ€”it’s cleaner and easier to configure. Use setTimeout in Code node when you need dynamic delays (like exponential backoff) or when the delay depends on API response data (like Retry-After headers). The Wait node pauses the entire workflow execution; setTimeout only pauses within that specific Code node.

How do I handle rate limits across multiple n8n workflows?

Use n8n’s static data with the β€˜global’ scope to share rate limit tracking across workflows: $getWorkflowStaticData('global'). Store timestamps of recent requests and check this shared log before making new requests. Alternatively, stagger your workflow schedules so they don’t run simultaneously, or use a dedicated rate-limiting service external to n8n.

Ready to Automate Your Business?

Tell us what you need automated. We'll build it, test it, and deploy it fast.

βœ“ 48-72 Hour Turnaround
βœ“ Production Ready
βœ“ Free Consultation
⚑

Create Your Free Account

Sign up once, use all tools free forever. We require accounts to prevent abuse and keep our tools running for everyone.

or

By signing up, you agree to our Terms of Service and Privacy Policy. No spam, unsubscribe anytime.