Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/get-convex/rate-limiter/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The useRateLimit hook provides real-time rate limit information in your React components. It monitors the current rate limit status and automatically updates when capacity changes, allowing you to show users when they can retry an action.

Function Signature

function useRateLimit(
  getRateLimitValueQuery: GetRateLimitValueQuery,
  opts?: UseRateLimitOptions
): {
  status: { ok: true; retryAt: undefined } | { ok: false; retryAt: number } | undefined;
  check: (ts?: number, count?: number) => CheckResult | undefined;
}

Type Definitions

type GetRateLimitValueQuery = FunctionReference<
  "query",
  "public",
  GetValueArgs,
  GetValueReturns
>;

type UseRateLimitOptions = {
  name?: string;
  key?: string;
  count?: number;
  sampleShards?: number;
  getServerTimeMutation?: GetServerTimeMutation;
  config?: RateLimitConfig;
};

type GetServerTimeMutation = FunctionReference<
  "mutation",
  "public",
  Record<string, never>,
  number
>;

Parameters

getRateLimitValueQuery
GetRateLimitValueQuery
required
The query function returned by rateLimiter.hookAPI().getRateLimit. This query retrieves the current rate limit value from the server.
opts
UseRateLimitOptions
Optional configuration object for the hook.

Return Value

status
object | undefined
The current rate limit status. undefined while loading.When ok: true:When ok: false:
check
function
A function to manually check the rate limit at a specific time or for a different token count.Signature: (ts?: number, count?: number) => CheckResult | undefinedReturns CheckResult | undefined:
type CheckResult = {
  value: number;        // Current token value
  ts: number;          // Client timestamp of the value
  config: RateLimitConfig;  // The rate limit configuration
  shard: number;       // The shard number
  ok: boolean;         // Whether the check passed
  retryAt?: number;    // Client timestamp when retry would succeed
}

Usage Example

Basic React Component

import { useRateLimit } from "@convex-dev/rate-limiter/react";
import { api } from "./convex/_generated/api";

function SendMessageButton() {
  const { status, check } = useRateLimit(
    api.messages.getRateLimit,
    {
      // Recommended: sync client/server clocks
      getServerTimeMutation: api.messages.getServerTime,
      // Check if we have capacity for 1 message
      count: 1,
    }
  );

  if (!status) {
    return <button disabled>Loading...</button>;
  }

  if (!status.ok) {
    const waitSeconds = Math.ceil((status.retryAt - Date.now()) / 1000);
    return (
      <button disabled>
        Wait {waitSeconds}s before sending
      </button>
    );
  }

  return <button onClick={handleSend}>Send Message</button>;
}

With Manual Checking

function TokenConsumer() {
  const [tokenCount, setTokenCount] = useState(10);
  const { status, check } = useRateLimit(
    api.llm.getRateLimit,
    {
      getServerTimeMutation: api.llm.getServerTime,
    }
  );

  // Check if we have capacity for the current token count
  const result = check(Date.now(), tokenCount);

  return (
    <div>
      <input
        type="number"
        value={tokenCount}
        onChange={(e) => setTokenCount(Number(e.target.value))}
      />
      {result && (
        <div>
          {result.ok ? (
            <p>Available capacity: {result.value} tokens</p>
          ) : (
            <p>Retry in {Math.ceil((result.retryAt - Date.now()) / 1000)}s</p>
          )}
        </div>
      )}
    </div>
  );
}

Time Synchronization

The hook uses getServerTimeMutation to synchronize the client and server clocks. This is highly recommended because:
  1. Client clocks can be inaccurate or intentionally set incorrectly
  2. The rate limit calculations happen server-side using server time
  3. Without synchronization, retryAt values may be incorrect

How It Works

// The hook measures latency and calculates the offset
const clientTime = Date.now();
const serverTime = await convex.mutation(getServerTimeMutation, {});
const latency = Date.now() - clientTime;
const timeOffset = serverTime - clientTime - latency / 2;

// All times are then adjusted
const adjustedRetryAt = serverRetryTime - timeOffset;

Server Setup

The getServerTime mutation is automatically included when you use hookAPI():
// In convex/messages.ts
export const { getRateLimit, getServerTime } = rateLimiter.hookAPI(
  "sendMessage",
  {
    key: async (ctx) => await getUserId(ctx),
  }
);

Advanced Patterns

See React Hooks Guide for more examples including:
  • Displaying countdown timers
  • Optimistic UI updates
  • Multi-token operations
  • Custom retry strategies

Build docs developers (and LLMs) love