How to fix over_sms_send_rate_limit: SMS send rate limit exceeded in Supabase

SupabaseINTERMEDIATEMEDIUMUpdated Dec 22, 2025· 96 views

The "over_sms_send_rate_limit: SMS send rate limit exceeded" error occurs when Supabase Auth blocks SMS sending due to rate limiting. This protection prevents SMS bombing attacks and excessive usage, typically triggered by too many authentication attempts to a single phone number within a short time period or exceeding overall project SMS quotas.

Quick fix

Fixes over_sms_send_rate_limit

// Client-side rate limiting for SMS requests
let lastSmsRequestTime = 0;
const SMS_COOLDOWN_MS = 60000; // 60 seconds between requests

async function requestSmsOtp(phoneNumber) {
  const now = Date.now();
  const timeSinceLastRequest = now - lastSmsRequestTime;

  if (timeSinceLastRequest < SMS_COOLDOWN_MS) {
    const remainingSeconds = Math.ceil((SMS_COOLDOWN_MS - timeSinceLastRequest) / 1000);
    throw new Error(`Please wait ${remainingSeconds} seconds before requesting another code`);
  }

  lastSmsRequestTime = now;

  const { error } = await supabase.auth.signInWithOtp({
    phone: phoneNumber,
    options: { channel: 'sms' }
  });

  if (error) {
    if (error.code === 'over_sms_send_rate_limit') {
      // Show user-friendly message with longer cooldown
      return {
        success: false,
        message: 'Too many attempts. Please wait 5 minutes before trying again.',
        cooldown: 300000 // 5 minutes
      };
    }
    throw error;
  }

  return { success: true, message: 'SMS sent successfully' };
}
  1. Implement client-side rate limiting and cooldown periods
  2. Add CAPTCHA or bot protection for public SMS forms
  3. Monitor and analyze SMS rate limit events
  4. Implement fallback authentication methods
supabase — error
// Client-side rate limiting for SMS requests
let lastSmsRequestTime = 0;
const SMS_COOLDOWN_MS = 60000; // 60 seconds between requests
async function requestSmsOtp(phoneNumber) {
const now = Date.now();
const timeSinceLastRequest = now - lastSmsRequestTime;
if (timeSinceLastRequest < SMS_COOLDOWN_MS) {
const remainingSeconds = Math.ceil((SMS_COOLDOWN_MS - timeSinceLastRequest) / 1000);
throw new Error(`Please wait ${remainingSeconds} seconds before requesting another code`);
}
lastSmsRequestTime = now;
const { error } = await supabase.auth.signInWithOtp({
phone: phoneNumber,
options: { channel: 'sms' }
});
if (error) {
if (error.code === 'over_sms_send_rate_limit') {
// Show user-friendly message with longer cooldown
return {
success: false,
message: 'Too many attempts. Please wait 5 minutes before trying again.',
cooldown: 300000 // 5 minutes
};
}
throw error;
}
return { success: true, message: 'SMS sent successfully' };
}
over_sms_send_rate_limit: SMS send rate limit exceeded

What this error means

The "over_sms_send_rate_limit" error is a Supabase Auth security feature that protects against SMS abuse and excessive usage. When this error occurs, Supabase has detected that SMS sending attempts have exceeded predefined rate limits for either a specific phone number or your entire project. This rate limiting serves several important purposes: 1. **Security**: Prevents SMS bombing attacks where malicious actors attempt to flood a phone number with authentication messages 2. **Cost control**: Limits unexpected SMS charges by preventing runaway loops or misconfigured applications 3. **Compliance**: Helps maintain compliance with carrier regulations and anti-spam policies 4. **Resource protection**: Ensures fair usage of Supabase's SMS infrastructure The error typically appears when: - A user requests too many SMS OTP codes in rapid succession - Your application has a bug causing repeated SMS sending attempts - Multiple users are simultaneously triggering SMS authentication - You've exceeded your project's daily or monthly SMS quota

Typical symptoms

  • Phone authentication fails with "over_sms_send_rate_limit: SMS send rate limit exceeded" error
  • Users report not receiving SMS OTP codes after multiple attempts
  • Error appears in Supabase Auth logs with status code 429 (Too Many Requests)
  • SMS sending works initially but fails after several attempts
  • Authentication flows work for some users but fail for others who have recently requested SMS
  • Error occurs during development/testing when sending many test SMS messages

Common causes

  1. User requesting too many SMS OTP codes in a short time period (e.g., rapid retry attempts)
  2. Application bug causing infinite loops or repeated SMS sending attempts
  3. Multiple users sharing the same phone number attempting authentication simultaneously
  4. Exceeding Supabase project-level SMS rate limits (default limits apply to all projects)
  5. Development/testing environments sending excessive SMS during testing
  6. Malicious actors attempting SMS bombing attacks on your application
  7. Cached or stale application state causing repeated authentication attempts

How to fix "over_sms_send_rate_limit: SMS send rate limit exceeded"

1Implement client-side rate limiting and cooldown periods

Add client-side protections to prevent users from triggering rate limits:

javascript
// Client-side rate limiting for SMS requests
let lastSmsRequestTime = 0;
const SMS_COOLDOWN_MS = 60000; // 60 seconds between requests

async function requestSmsOtp(phoneNumber) {
  const now = Date.now();
  const timeSinceLastRequest = now - lastSmsRequestTime;

  if (timeSinceLastRequest < SMS_COOLDOWN_MS) {
    const remainingSeconds = Math.ceil((SMS_COOLDOWN_MS - timeSinceLastRequest) / 1000);
    throw new Error(`Please wait ${remainingSeconds} seconds before requesting another code`);
  }

  lastSmsRequestTime = now;

  const { error } = await supabase.auth.signInWithOtp({
    phone: phoneNumber,
    options: { channel: 'sms' }
  });

  if (error) {
    if (error.code === 'over_sms_send_rate_limit') {
      // Show user-friendly message with longer cooldown
      return {
        success: false,
        message: 'Too many attempts. Please wait 5 minutes before trying again.',
        cooldown: 300000 // 5 minutes
      };
    }
    throw error;
  }

  return { success: true, message: 'SMS sent successfully' };
}

Best practices:
- Minimum 60-second cooldown between SMS requests per phone number
- Show clear countdown timers to users
- Disable SMS request buttons during cooldown periods
- Implement exponential backoff for retries

2Add CAPTCHA or bot protection for public SMS forms

Protect SMS endpoints from automated attacks:

javascript
// Using reCAPTCHA v3 with Supabase
async function sendSmsWithCaptcha(phoneNumber) {
  // Get reCAPTCHA token
  const token = await grecaptcha.execute('YOUR_SITE_KEY', {action: 'sms_request'});

  // Verify token with your backend
  const captchaValid = await verifyCaptchaToken(token);

  if (!captchaValid) {
    throw new Error('CAPTCHA verification failed');
  }

  // Proceed with SMS request
  const { error } = await supabase.auth.signInWithOtp({
    phone: phoneNumber,
    options: { channel: 'sms' }
  });

  return { error };
}

// Alternative: hCaptcha or Turnstile
async function sendSmsWithTurnstile(phoneNumber) {
  const token = await turnstile.execute('YOUR_WIDGET_ID');

  const response = await fetch('/api/verify-turnstile', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ token })
  });

  if (!response.ok) {
    throw new Error('Bot protection verification failed');
  }

  const { error } = await supabase.auth.signInWithOtp({
    phone: phoneNumber,
    options: { channel: 'sms' }
  });

  return { error };
}

Implementation options:
- Google reCAPTCHA v3 (invisible)
- hCaptcha
- Cloudflare Turnstile
- Custom challenge-response mechanisms

3Monitor and analyze SMS rate limit events

Set up monitoring to identify patterns and abuse:

javascript
// Log rate limit events for analysis
async function handleSmsError(error, phoneNumber, context) {
  const logEntry = {
    timestamp: new Date().toISOString(),
    errorCode: error.code,
    errorMessage: error.message,
    phoneNumber: maskPhoneNumber(phoneNumber), // Mask for privacy
    context: context,
    userAgent: navigator.userAgent,
    ipAddress: await getClientIp() // From your backend
  };

  // Send to analytics service
  await fetch('/api/log/sms-error', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(logEntry)
  });

  // Check Supabase logs for more details
  console.warn('SMS rate limit triggered:', {
    phoneNumber: maskPhoneNumber(phoneNumber),
    time: new Date().toISOString(),
    errorDetails: error
  });
}

// Check Supabase Dashboard for logs:
// 1. Go to Project → Authentication → Logs
// 2. Filter for "over_sms_send_rate_limit" events
// 3. Look for patterns:
//    - Same IP address making many requests
//    - Same phone number receiving excessive SMS
//    - Time-based patterns indicating automated attacks

Monitoring tools:
- Supabase Authentication Logs dashboard
- Custom logging to analytics platform (Segment, Mixpanel, etc.)
- Error tracking (Sentry, Bugsnag)
- Security monitoring (fail2ban patterns, IP blocking)

4Implement fallback authentication methods

Provide alternatives when SMS rate limits are hit:

javascript
// Multi-method authentication with fallbacks
async function authenticateUser(identifier, method = 'auto') {
  try {
    if (method === 'sms' || method === 'auto') {
      const { error } = await supabase.auth.signInWithOtp({
        phone: identifier,
        options: { channel: 'sms' }
      });

      if (!error) return { success: true, method: 'sms' };

      if (error.code === 'over_sms_send_rate_limit') {
        console.warn('SMS rate limited, trying email fallback');
        // Check if identifier could be an email
        if (identifier.includes('@')) {
          return await authenticateUser(identifier, 'email');
        }
        // Offer alternative methods
        return {
          success: false,
          method: 'sms',
          error: 'SMS rate limited. Please try again in 5 minutes or use email authentication.',
          fallbacks: ['email', 'magic_link']
        };
      }
    }

    if (method === 'email' || method === 'auto') {
      const { error } = await supabase.auth.signInWithOtp({
        email: identifier
      });

      if (!error) return { success: true, method: 'email' };
    }

    // Magic link fallback
    if (method === 'magic_link') {
      const { error } = await supabase.auth.signInWithOtp({
        email: identifier,
        options: {
          emailRedirectTo: 'https://yourapp.com/auth/callback'
        }
      });

      if (!error) return { success: true, method: 'magic_link' };
    }

    throw new Error('All authentication methods failed');

  } catch (err) {
    console.error('Authentication failed:', err);
    return { success: false, error: err.message };
  }
}

Fallback options:
- Email OTP authentication
- Magic links
- Social login (Google, GitHub, etc.)
- One-time backup codes
- Time-based waiting periods with clear user communication

5Optimize SMS usage and implement caching

Reduce unnecessary SMS sends:

javascript
// Cache successful authentications to reduce SMS volume
const smsCache = new Map();

async function getCachedSmsAuth(phoneNumber) {
  const cacheKey = `sms-auth:${phoneNumber}`;
  const cached = smsCache.get(cacheKey);

  if (cached && Date.now() - cached.timestamp < 300000) { // 5 minute cache
    return { cached: true, data: cached.data };
  }

  // Remove expired entries
  for (const [key, value] of smsCache.entries()) {
    if (Date.now() - value.timestamp > 300000) {
      smsCache.delete(key);
    }
  }

  return { cached: false };
}

// Implement resend logic with increasing delays
async function resendSmsOtp(phoneNumber, attempt = 1) {
  const baseDelay = 60000; // 60 seconds
  const maxDelay = 300000; // 5 minutes
  const delay = Math.min(baseDelay * Math.pow(2, attempt - 1), maxDelay);

  if (attempt > 3) {
    throw new Error('Maximum resend attempts reached. Please contact support.');
  }

  await new Promise(resolve => setTimeout(resolve, delay));

  const { error } = await supabase.auth.signInWithOtp({
    phone: phoneNumber,
    options: { channel: 'sms' }
  });

  return { error, nextAttemptDelay: Math.min(delay * 2, maxDelay) };
}

// Usage
const result = await resendSmsOtp('+1234567890', 1);
if (result.error && result.error.code === 'over_sms_send_rate_limit') {
  console.log(`Next attempt available in ${result.nextAttemptDelay / 1000} seconds`);
}

Optimization strategies:
- Cache authentication states to prevent duplicate SMS sends
- Implement exponential backoff for resend requests
- Use session-based authentication where appropriate
- Consider push notifications or in-app messages as alternatives

6Contact Supabase support for rate limit adjustments

If legitimate traffic is hitting rate limits:

## When to contact support:
1. High-volume legitimate traffic: Your application has many genuine users needing SMS auth
2. Business-critical applications: SMS authentication is essential for your service
3. Scheduled maintenance/testing: Need temporary limit increases for testing

## Information to provide:
- Your Supabase project ID
- Current error rates and patterns
- Estimated SMS volume requirements
- Use case details (B2C, B2B, internal tool, etc.)
- Security measures you have in place (CAPTCHA, rate limiting, etc.)

## Alternative solutions to discuss:
1. Custom rate limit tiers: Higher limits for verified business use cases
2. Burst allowances: Temporary increases for specific events
3. Enterprise plans: Higher limits available with paid plans
4. Custom SMS providers: Using your own Twilio/MessageBird account with higher limits

## Important considerations:
- Rate limits exist for security and cost reasons
- Supabase may require additional security measures before increasing limits
- Consider implementing email or social login as primary methods
- Evaluate if SMS is truly necessary for your use case

## Contact methods:
1. Supabase Dashboard Support: Project → Support
2. Discord Community: #help channel for advice
3. Email Support: support@supabase.com for business inquiries

Advanced notes

## Understanding Supabase SMS Rate Limits

### Default Rate Limits (Subject to Change)
Supabase imposes several layers of rate limiting for SMS authentication:

1. Per-phone number limits:
- Typically 5-10 SMS attempts per hour per phone number
- Prevents SMS bombing attacks on individual users

2. Per-project limits:
- Overall SMS sending capacity per project
- Varies based on plan (Free, Pro, Enterprise)
- Includes both authentication and custom SMS sends

3. Geographic limits:
- Some countries/carriers have stricter limits
- International SMS may have additional restrictions

### Rate Limit Headers and Responses
When rate limited, Supabase returns:
- HTTP Status: 429 Too Many Requests
- Error code: over_sms_send_rate_limit
- Retry-After header (if available): Suggested wait time in seconds

### Security Implications
Rate limiting is a critical security feature:
- Prevents denial-of-wallet attacks: SMS costs money; unlimited sending could incur huge bills
- Protects user privacy: Prevents harassment via SMS bombing
- Compliance: Meets carrier requirements for A2P (application-to-person) messaging
- Resource fairness: Ensures all Supabase users have access to SMS services

### Monitoring and Alerting Setup
Implement comprehensive monitoring:

yaml
# Example alert configuration (Prometheus + Alertmanager)
groups:
  - name: supabase-sms-alerts
    rules:
      - alert: HighSMSRateLimitRate
        expr: rate(supabase_sms_rate_limit_errors_total[5m]) > 0.1
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High rate of SMS rate limiting"
          description: "{{ $value }} SMS rate limit errors per second"

      - alert: SMSFailureRateHigh
        expr: sum(rate(supabase_sms_failures_total[5m])) / sum(rate(supabase_sms_attempts_total[5m])) > 0.1
        for: 10m
        labels:
          severity: critical
        annotations:
          summary: "High SMS failure rate"
          description: "{{ $value | humanizePercentage }} of SMS attempts are failing"

### Alternative Authentication Strategies
Consider these alternatives to reduce SMS dependency:

1. Email-based authentication: Lower cost, fewer rate limits
2. Social providers: Google, GitHub, etc. handle their own rate limiting
3. WebAuthn/Passkeys: Passwordless, secure, no SMS costs
4. Magic links: Email-based, good user experience
5. TOTP apps: Google Authenticator, Authy, etc.
6. Backup codes: For emergency access when SMS fails

### Carrier-Specific Considerations
Different carriers have different SMS handling:

- Twilio: Detailed error codes for carrier rejections
- MessageBird: Regional delivery optimizations
- Vonage: Strong European coverage
- Local providers: Often cheaper but may have delivery issues

### Legal and Compliance Notes
- GDPR: Phone numbers are personal data; ensure proper consent
- TCPA (US): Requires prior express consent for marketing SMS
- CASL (Canada): Similar consent requirements
- 10DLC (US): Registration required for business SMS
- Carrier filtering: Some carriers block short codes or certain content

Frequently asked questions

What does "over_sms_send_rate_limit" mean?
The "over_sms_send_rate_limit" error is a Supabase Auth security feature that protects against SMS abuse and excessive usage. When this error occurs, Supabase has detected that SMS sending attempts have exceeded predefined rate limits for either a specific phone number or your entire project. This rate limiting serves several important purposes: 1.
How do I fix "over_sms_send_rate_limit"?
The "over_sms_send_rate_limit: SMS send rate limit exceeded" error occurs when Supabase Auth blocks SMS sending due to rate limiting. This protection prevents SMS bombing attacks and excessive usage, typically triggered by too many authentication attempts to a single phone number within a short time period or exceeding overall project SMS quotas.
What causes "over_sms_send_rate_limit"?
User requesting too many SMS OTP codes in a short time period (e.g., rapid retry attempts) Application bug causing infinite loops or repeated SMS sending attempts Multiple users sharing the same phone number attempting authentication simultaneously
Is the "over_sms_send_rate_limit" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading