Rate Limiting
Alfred402 implements a robust rate limiting system to prevent abuse and ensure fair usage across all users.
Overview
The rate limiting system enforces a 50-second cooldown between messages, with protection against bypass attempts through page refreshes.
How It Works
Client-Side Implementation
The rate limit is enforced in the chat interface (app/app/page.js):
const [cooldownRemaining, setCooldownRemaining] = useState(0);
const [lastSubmitTime, setLastSubmitTime] = useState(0);
const handleFormSubmit = (e) => {
e.preventDefault();
const now = Date.now();
const timeSinceLastSubmit = (now - lastSubmitTime) / 1000;
if (timeSinceLastSubmit < 50 && lastSubmitTime > 0) {
const remaining = Math.ceil(50 - timeSinceLastSubmit);
setCooldownRemaining(remaining);
return;
}
// Allow submission
setLastSubmitTime(now);
setCooldownRemaining(50);
localStorage.setItem('lastSubmitTime', now.toString());
sendMessage({ text: finalMessage });
};Countdown Timer
A live countdown displays the remaining time:
Refresh Protection
The cooldown persists across page refreshes using localStorage:
User Experience
Before Cooldown
✅ Input fields are enabled
✅ Send button shows send icon
✅ User can type and submit messages
During Cooldown
❌ Input fields are disabled
⏱️ Send button shows countdown (e.g., "47s")
📝 Message displays: "Please wait X seconds before sending another message"
🔒 Cannot bypass by refreshing page
After Cooldown
✅ Input fields re-enable automatically
✅ Send button returns to normal
✅ User can submit new messages
Visual Indicators
Send Button States
Input Field States
Status Message
Configuration
Changing the Cooldown Duration
To modify the 50-second cooldown, update these locations in app/app/page.js:
Line 43-46: Cooldown check
Line 58: Initial cooldown setting
Line 46-49: Restoration check
Example: Change to 30 seconds
Replace all instances of 50 with 30.
Server-Side Alignment
The API route has a matching timeout in app/api/chat/route.js:
This should match or exceed your cooldown duration.
Implementation Details
localStorage Schema
Key: lastSubmitTime
Value: Timestamp in milliseconds (string)
Example:
Cleanup Strategy
localStorage is cleaned up:
When cooldown reaches 0
When expired timestamp is detected on mount
Never accumulates stale data
Security Considerations
Cannot Be Bypassed By:
✅ Refreshing the page - Timestamp persists in localStorage ✅ Opening new tab - Same localStorage across tabs ✅ Developer tools - Client-side only, expected behavior ✅ Clearing input - Cooldown tracks time, not input
Can Be Bypassed By:
⚠️ Clearing localStorage - Expected; user's choice ⚠️ Private/Incognito mode - Different storage context ⚠️ Different browser - Separate storage
Why Client-Side Only?
Simplicity: No backend state management needed
Scalability: No database or session storage required
Privacy: No tracking of user behavior
Fair usage: Prevents accidental spam, not malicious abuse
For production systems requiring stronger enforcement, consider:
Session-based rate limiting
IP-based rate limiting
Authentication-based quotas
Best Practices
For Users
Wait patiently - The AI needs time to perform web searches
Craft detailed questions - Make each query count
Use follow-ups wisely - Build on previous context
For Developers
Match server timeout - Keep
maxDuration>= cooldownTest edge cases - Verify refresh protection works
Communicate clearly - User message explains the wait
Consider UX - Show countdown for transparency
Troubleshooting
Cooldown Not Working
Symptoms: Can send multiple messages immediately
Solutions:
Check browser console for JavaScript errors
Verify localStorage is enabled
Ensure useEffect hooks are running
Check that state updates are occurring
Cooldown Stuck
Symptoms: Countdown never reaches 0
Solutions:
Refresh the page
Clear localStorage manually:
Check interval cleanup in useEffect
Cooldown Resets on Refresh
Symptoms: Refresh bypasses cooldown
Solutions:
Verify localStorage restoration useEffect exists
Check that 'lastSubmitTime' is being stored
Ensure parseInt is parsing correctly
Alternative Approaches
Session-Based
Pros: Server-enforced, more secure Cons: Requires backend state, less scalable
Token Bucket
Pros: Allows bursts, more flexible Cons: Complex implementation, needs backend
Future Enhancements
Potential improvements:
Variable cooldowns - Shorter for simple queries, longer for complex
User accounts - Track quotas per user
Premium tiers - Reduced/no cooldown for paid users
Adaptive limiting - Adjust based on system load
Related Documentation
Questions? See Common Issues or join Discord.
Last updated
