Rate Limiting

Miko402 enforces intelligent rate limiting to ensure system stability, fair access, and protection against unintended overspending across autonomous payment flows.

Overview

The rate limiting system applies a 50-second cooldown between messages, with persistence mechanisms that prevent circumvention through page refreshes or tab switching.

How It Works

Client-Side Enforcement

Rate limiting is implemented directly in the chat interface (app/app/page.js), gating message submission at the UI layer:

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;
  }

  setLastSubmitTime(now);
  setCooldownRemaining(50);
  localStorage.setItem('lastSubmitTime', now.toString());

  sendMessage({ text: finalMessage });
};

Live Countdown

A real-time countdown displays the remaining cooldown period, providing clear feedback on when the next message can be sent:

Refresh Persistence

The cooldown survives page refreshes via localStorage, ensuring the timer cannot be reset by reloading:

User Experience

Ready State

  • Input fields are active and accepting text

  • Send button displays the standard send icon

  • Messages submit normally on click or Enter

Cooldown Active

  • Input fields are disabled

  • Send button displays a live countdown (e.g., 47s)

  • A crimson status message shows the remaining wait time

  • Page refresh does not reset the timer

Cooldown Complete

  • Input fields re-enable automatically

  • Send button returns to its default state

  • The next message can be submitted immediately

Visual Indicators

Send Button States

Status Message

Configuration

Adjusting the Cooldown Duration

To modify the 50-second cooldown, update all instances in app/app/page.js:

  1. Cooldown check — the conditional threshold

  2. Initial cooldown — the value set on successful submit

  3. Refresh restoration — the persistence check on mount

Replace every instance of 50 with your desired duration in seconds.

Server-Side Alignment

The API route includes a matching timeout configuration:

This value should match or exceed your cooldown duration to ensure requests complete within the allowed window.

Implementation Details

Storage Schema

Key
Value
Scope

lastSubmitTime

Timestamp in milliseconds (string)

localStorage

Automatic Cleanup

localStorage is cleaned when the cooldown reaches zero or when an expired timestamp is detected on page load. No stale data accumulates.

Bypass Analysis

Protected against:

  • Page refresh (timestamp persists in localStorage)

  • New tab in the same browser (shared localStorage scope)

  • Input field clearing (cooldown tracks time, not content)

Not protected against:

  • Manual localStorage clearing (intentional user action)

  • Private/Incognito mode (isolated storage context)

  • Different browser (separate storage entirely)

Why Client-Side Only?

Miko402 implements client-side rate limiting for simplicity, scalability, and privacy. No backend state management, database, or user tracking is required. This approach prevents accidental spam while maintaining a lightweight architecture.

For production deployments requiring stronger enforcement, consider session-based, IP-based, or wallet-authenticated rate limiting.

Best Practices

For Users

  • Craft detailed requests — maximize the value of each message during the cooldown window

  • Batch related items — combine multiple questions or service requests into a single message

  • Use the wait time — review Miko402's response and plan your follow-up

For Developers

  • Match server timeout — keep maxDuration ≥ cooldown duration

  • Test edge cases — verify refresh persistence works correctly across browsers

  • Communicate clearly — ensure the countdown and status messaging are visible and accessible

Troubleshooting

Symptom
Solution

Can send multiple messages immediately

Check browser console for JS errors; verify localStorage is enabled

Countdown never reaches zero

Refresh the page or clear localStorage manually: localStorage.removeItem('lastSubmitTime')

Cooldown resets on refresh

Verify the localStorage restoration useEffect is present and parseInt parses correctly

Future Enhancements

  • Variable cooldowns — shorter for simple queries, longer for complex payment flows

  • $MIKO holder tiers — reduced cooldown for token holders

  • Adaptive limiting — dynamic adjustment based on system load

  • Server-side enforcement — stronger guarantees for production deployments


Last updated