Stop webhook flooding before it starts. Add production-grade rate limiting to any n8n webhook in minutes - reject abusive traffic before expensive workflow logic executes.
Webhook receives POST request
Identity extracted from headers:
x-api-key) → per-client limitingX-Forwarded-For / x-real-ip) → per-IP limitingGuard decides allow or deny:
POST /api/v1/guard/{route:identity}/counterAllowed → your business logic executes → 200 OK
Denied → immediate 429 Too Many Requests + Retry-After header
Client → Webhook → Identity → Guard → Allowed? → Business Logic → 200 OK
↓ NO
429 + Retry-After
That's it. One credential, one API.
GuardCheck nodeConfig node with your limits:| Variable | Default | Description |
|---|---|---|
rate_limit |
30 |
Max requests per window |
window_sec |
60 |
Window in seconds |
identity_mode |
ip |
ip or apiKey |
route_name |
webhook |
Endpoint name |
BusinessLogic node with your workflowAccess original request:
const body = $('Webhook').first().json.body;
const headers = $('Webhook').first().json.headers;
Bash (Linux/macOS):
for i in {1..50}; do
curl -s -o /dev/null -w "%{http_code}\n" \
-X POST https://your-n8n.com/webhook/rate-limited-endpoint \
-H "Content-Type: application/json" \
-d '{"test": true}'
done
PowerShell (Windows):
1..50 | ForEach-Object {
(Invoke-WebRequest -Uri "https://your-n8n.com/webhook/rate-limited-endpoint" -Method POST -Body '{"test":true}' -ContentType "application/json" -UseBasicParsing).StatusCode
}
Expected: First 30 → 200, remaining → 429
curl -H "X-Forwarded-For: 1.2.3.4, 5.6.7.8" \
-X POST https://your-n8n.com/webhook/rate-limited-endpoint
Identity key should use 1.2.3.4 (first IP from chain).
{
"ok": true,
"data": { "message": "Request processed successfully" }
}
Headers: Retry-After: 17
{
"ok": false,
"error": "rate_limited",
"retryAfter": 17
}
| Section | Nodes | Description |
|---|---|---|
| Rate Limit Check | Webhook → Config → BuildIdentity → GuardCheck → IfAllowed | Extract identity, check Guard |
| Allowed Path | BusinessLogic → RespondOk | Your logic + 200 response |
| Denied Path | BuildDeniedResponse → RespondRateLimited | 429 + Retry-After |
Total: 9 nodes. Minimal by design.
Guard handles application-level rate decisions, not network security.
Best for public webhooks where clients don't have API keys.
X-Forwarded-For: 1.2.3.4, 5.6.7.8 → identity = "1.2.3.4"
x-real-ip: 10.0.0.1 → identity = "10.0.0.1"
⚠️ IP addresses can be shared (NAT, mobile carriers, offices).
Best for authenticated endpoints with per-client keys.
x-api-key: client_abc123 → identity = "client_abc123"
Falls back to IP if header is missing.
| Use Case | rate_limit | window_sec | Result |
|---|---|---|---|
| Burst protection | 30 | 60 | 30/min |
| API rate limiting | 100 | 3600 | 100/hour |
| LLM cost protection | 10 | 60 | 10/min |
| Daily limit | 1000 | 86400 | 1000/day |
Use different route_name values to create separate rate limits:
Config A: route_name = "orders" → key = "orders:1.2.3.4"
Config B: route_name = "payments" → key = "payments:1.2.3.4"
Each route has independent counters.
Default: Fail-open - Guard API uses failOpen=true, so Guard outage doesn't block traffic.
To switch to fail-closed: change failOpen query parameter to false in GuardCheck node.
Getting duplicate webhook deliveries? Add Ainoflow Shield before your business logic - one trigger, one execution, guaranteed. Guard + Shield = rate limiting + deduplication on the same endpoint.
allowPolicyOverwrite=true is set for easy demo/testing - Config node values always apply. Production: set to false in GuardCheck query params to lock policy and prevent hidden config driftWant to add temporary bans, cost protection mode, multi-tier rate limiting, or per-client usage dashboards?
Ainova Systems - We build custom AI automation infrastructure and safety layers for production workflows.
Tags: webhook, rate-limiting, security, guard, burst-protection, api-protection, ainoflow, production, webhook-security, cost-control