Rate Limits
Understanding and configuring rate limiting for form submissions
Rate Limits
Understanding and configuring rate limiting for form submissions.
Overview
Rate limiting prevents abuse and ensures fair usage of FormFeeder's resources. Different types of limits apply at various levels to protect both the service and your forms from spam and automated attacks.
Types of Rate Limits
Global Rate Limits
Applied to all requests from a single IP address:
- Default: 100 requests per minute per IP address
- Applies to: All endpoints including form submissions
- Reset: Rolling window (not fixed intervals)
- Headers: Rate limit information included in responses
Form-Specific Rate Limits
Applied per form per IP address:
- Default: 10 submissions per minute per IP per form
- Configurable: Can be adjusted per form
- Privacy Mode: Same limits apply
- Bypass: Not possible without API key authentication
File Upload Rate Limits
Additional limits for file uploads:
- File Size: 5MB per file (default)
- Total Size: 10MB per submission (default)
- File Count: 5 files per submission (default)
- Upload Rate: Bandwidth throttling for large files
Rate Limit Headers
All responses include rate limiting headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640995200
X-RateLimit-Type: global
Header Descriptions
| Header | Description |
|---|---|
X-RateLimit-Limit |
Maximum requests allowed in time window |
X-RateLimit-Remaining |
Requests remaining in current window |
X-RateLimit-Reset |
Unix timestamp when limit resets |
X-RateLimit-Type |
Type of limit (global or form) |
Handling Rate Limits
HTTP Response
When rate limited, you'll receive a 429 Too Many Requests response:
{
"success": false,
"message": "Rate limit exceeded",
"code": "RATE_LIMIT_EXCEEDED",
"retryAfter": 30
}
JavaScript Error Handling
async function submitForm(formData) {
try {
const response = await fetch('https://api.formfeeder.io/v1/form/abc123', {
method: 'POST',
body: formData
});
if (response.status === 429) {
const data = await response.json();
const retryAfter = data.retryAfter || 60;
// Show user-friendly message
showError(`Too many requests. Please wait ${retryAfter} seconds and try again.`);
// Optionally implement automatic retry
setTimeout(() => submitForm(formData), retryAfter * 1000);
return;
}
// Handle other responses...
} catch (error) {
console.error('Submission error:', error);
}
}
Retry Logic Implementation
async function submitWithRetry(formData, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch('https://api.formfeeder.io/v1/form/abc123', {
method: 'POST',
body: formData
});
if (response.ok) {
return await response.json();
}
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || Math.pow(2, attempt);
console.log(`Rate limited. Retrying in ${retryAfter} seconds (attempt ${attempt})`);
if (attempt < maxRetries) {
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
continue;
}
}
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
} catch (error) {
if (attempt === maxRetries) throw error;
// Exponential backoff for network errors
const delay = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
Best Practices
Client-Side Rate Limiting
Prevent hitting server limits by implementing client-side controls:
class FormSubmissionManager {
constructor() {
this.lastSubmission = 0;
this.minimumInterval = 1000; // 1 second between submissions
}
canSubmit() {
const now = Date.now();
return (now - this.lastSubmission) >= this.minimumInterval;
}
async submit(formData) {
if (!this.canSubmit()) {
throw new Error('Please wait before submitting again');
}
this.lastSubmission = Date.now();
// Proceed with submission...
}
}
Button Debouncing
Prevent accidental rapid clicks:
function debounceSubmit(button, delay = 2000) {
const originalText = button.textContent;
button.disabled = true;
button.textContent = 'Sending...';
setTimeout(() => {
button.disabled = false;
button.textContent = originalText;
}, delay);
}
User Feedback
Provide clear feedback when rate limits are encountered:
function showRateLimitMessage(retryAfter) {
const message = document.createElement('div');
message.className = 'alert alert-warning';
message.innerHTML = `
<strong>Slow down!</strong>
Too many submissions. Please wait ${retryAfter} seconds.
<div class="countdown" data-remaining="${retryAfter}"></div>
`;
document.getElementById('form-messages').appendChild(message);
// Countdown timer
startCountdown(message.querySelector('.countdown'));
}
function startCountdown(element) {
let remaining = parseInt(element.dataset.remaining);
const timer = setInterval(() => {
element.textContent = `${remaining} seconds remaining`;
remaining--;
if (remaining < 0) {
clearInterval(timer);
element.parentElement.remove();
}
}, 1000);
}
Configuration Options
Dashboard Configuration
For forms created through the dashboard, rate limits can be configured:
- Form Settings: Access form configuration
- Rate Limiting: Adjust per-minute limits
- File Limits: Configure file upload restrictions
- IP Whitelist: Bypass limits for trusted IPs (enterprise)
API Configuration
{
"rateLimit": {
"requests": 10,
"window": 60,
"burstLimit": 20
},
"fileUpload": {
"maxFileSize": 5242880,
"maxTotalSize": 10485760,
"maxFiles": 5
}
}
Configuration Parameters
| Parameter | Description | Default | Range |
|---|---|---|---|
requests |
Max requests per window | 10 | 1-100 |
window |
Time window in seconds | 60 | 30-300 |
burstLimit |
Temporary burst allowance | 20 | 1-200 |
maxFileSize |
Max size per file (bytes) | 5MB | 1MB-10MB |
maxFiles |
Max files per submission | 5 | 1-20 |
Monitoring and Analytics
Rate Limit Metrics
Dashboard users can view rate limiting metrics:
- Requests: Total requests and rate-limited requests
- Top IPs: Most active IP addresses
- Patterns: Time-based submission patterns
- Abuse Detection: Potential spam or bot traffic
Alerting
Set up alerts for unusual activity:
- High Rate Limit Hit Rate: When >50% requests are rate limited
- Unusual Traffic Spikes: Sudden increases in submission volume
- Geographic Anomalies: Traffic from unexpected locations
- Bot Detection: Automated submission patterns
Troubleshooting Rate Limits
Common Issues
- Legitimate Users Hit Limits: Adjust form-specific limits
- Development Testing: Use separate form IDs for testing
- CDN/Proxy Issues: May show single IP for multiple users
- Mobile Networks: Carrier-grade NAT may group users
Solutions
- Increase Limits: For high-traffic forms
- IP Whitelisting: For trusted sources (enterprise)
- Geographic Distribution: Use multiple forms for different regions
- Authentication: API keys bypass some limits
Debugging Commands
# Check current rate limit status
curl -I "https://api.formfeeder.io/v1/form/abc123" \
-H "Origin: https://example.com"
# Test rate limits
for i in {1..15}; do
echo "Request $i:"
curl -X POST "https://api.formfeeder.io/v1/form/abc123" \
-H "Content-Type: application/json" \
-H "Origin: https://example.com" \
-d '{"test": "data"}' \
-w "Status: %{http_code}\n" \
-s
done
Enterprise Features
Advanced Rate Limiting
Enterprise plans include additional features:
- Custom Rate Limits: Per-form customization
- IP Whitelisting: Bypass limits for trusted sources
- Geographic Rate Limits: Different limits by region
- Burst Protection: Advanced burst detection and handling
Priority Processing
- Fast Lane: Priority queue for enterprise forms
- Dedicated Resources: Separate processing pools
- SLA Guarantees: Response time commitments
- 24/7 Monitoring: Proactive issue detection
Contact [email protected] for enterprise rate limiting options.