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 getValue() method returns the current state of a rate limit without consuming any tokens. It provides detailed information including the current token value, timestamp, shard number, and configuration.

Method Signature

async getValue<Name extends string = keyof Limits & string>(
  ctx: RunQueryCtx,
  name: Name,
  ...options: Name extends keyof Limits & string
    ? [
        WithKnownNameOrInlinedConfig<
          Limits,
          Name,
          {
            key?: string;
            sampleShards?: number;
          }
        >?,
      ]
    : [
        WithKnownNameOrInlinedConfig<
          Limits,
          Name,
          {
            key?: string;
            sampleShards?: number;
          }
        >,
      ]
): Promise<GetValueReturns>

Parameters

ctx
RunQueryCtx
required
The context object from a query, including runQuery. This method works in both queries and mutations.
name
string
required
The name of the rate limit to query.
options
object
Optional configuration for retrieving the value.
key
string
The key for the rate limit instance. If not provided, retrieves the shared global rate limit value.
sampleShards
number
For sharded rate limits, the number of shards to sample. This affects which shard’s data is returned. Useful for debugging or monitoring specific shards.
config
RateLimitConfig
The rate limit configuration. Required only if the rate limit name was not defined in the RateLimiter constructor.

Return Type

GetValueReturns
object
Returns an object with the following properties:
value
number
required
The current number of available tokens. This can be a decimal for token bucket rate limits.
ts
number
required
The timestamp (in milliseconds) of when this value was last updated. For token bucket, this is the last refill time. For fixed window, this is the start of the current window.
shard
number
required
The shard number that this data came from. Useful for sharded rate limits to understand which shard is being used.
config
RateLimitConfig
required
The complete rate limit configuration for this limit, including all settings like kind, rate, period, capacity, etc.

Use with calculateRateLimit

The getValue() method pairs perfectly with the calculateRateLimit helper function for client-side rate limit tracking:
import { query } from "./_generated/server";
import { rateLimiter } from "./rateLimiter";

export const getMessageLimitStatus = query({
  handler: async (ctx) => {
    const userId = await getCurrentUser(ctx);
    
    return await rateLimiter.getValue(ctx, "sendMessage", {
      key: userId,
    });
  },
});
Then on the client:
import { calculateRateLimit } from "@convex-dev/rate-limiter";
import { useQuery } from "convex/react";
import { api } from "./convex/_generated/api";

function MessageComposer() {
  const limitStatus = useQuery(api.messages.getMessageLimitStatus);
  
  if (!limitStatus) return null;
  
  // Calculate current state on the client
  const current = calculateRateLimit(
    { value: limitStatus.value, ts: limitStatus.ts },
    limitStatus.config,
    Date.now()
  );
  
  return (
    <div>
      <p>Available tokens: {Math.floor(current.value)}</p>
      {current.retryAfter && (
        <p>Next token in: {Math.ceil(current.retryAfter / 1000)}s</p>
      )}
    </div>
  );
}

Examples

Basic Usage

import { query } from "./_generated/server";
import { rateLimiter } from "./rateLimiter";

export const checkApiQuota = query({
  handler: async (ctx) => {
    const userId = await getCurrentUser(ctx);
    
    const status = await rateLimiter.getValue(ctx, "apiCalls", {
      key: userId,
    });
    
    return {
      available: Math.floor(status.value),
      lastUpdated: new Date(status.ts).toISOString(),
      config: status.config,
    };
  },
});

Monitoring Dashboard

export const getRateLimitStats = query({
  handler: async (ctx) => {
    await requireAdmin(ctx);
    
    // Get stats for multiple rate limits
    const sendMessageGlobal = await rateLimiter.getValue(
      ctx,
      "sendMessage"
    );
    const signupGlobal = await rateLimiter.getValue(ctx, "freeTrialSignUp");
    
    return {
      sendMessage: {
        available: sendMessageGlobal.value,
        shard: sendMessageGlobal.shard,
      },
      signup: {
        available: signupGlobal.value,
        shard: signupGlobal.shard,
      },
    };
  },
});

User Quota Display

export const getUserQuotas = query({
  handler: async (ctx) => {
    const userId = await getCurrentUser(ctx);
    
    const [messages, uploads] = await Promise.all([
      rateLimiter.getValue(ctx, "sendMessage", { key: userId }),
      rateLimiter.getValue(ctx, "upload", { key: userId }),
    ]);
    
    return {
      messages: {
        available: Math.floor(messages.value),
        max: messages.config.capacity ?? messages.config.rate,
        refillRate: `${messages.config.rate} per ${messages.config.period}ms`,
      },
      uploads: {
        available: Math.floor(uploads.value),
        max: uploads.config.capacity ?? uploads.config.rate,
      },
    };
  },
});

Debug Specific Shard

export const debugRateLimitShard = query({
  args: { shardNumber: v.number() },
  handler: async (ctx, args) => {
    await requireAdmin(ctx);
    
    const status = await rateLimiter.getValue(ctx, "sendMessage", {
      sampleShards: args.shardNumber,
    });
    
    return {
      shard: status.shard,
      value: status.value,
      timestamp: status.ts,
      age: Date.now() - status.ts,
      config: status.config,
    };
  },
});

Calculate Time Until Next Token

import { calculateRateLimit } from "@convex-dev/rate-limiter";

export const getTimeUntilNextToken = query({
  handler: async (ctx) => {
    const userId = await getCurrentUser(ctx);
    const status = await rateLimiter.getValue(ctx, "sendMessage", {
      key: userId,
    });
    
    // Use calculateRateLimit to project future state
    const current = calculateRateLimit(
      { value: status.value, ts: status.ts },
      status.config,
      Date.now()
    );
    
    if (current.value >= 1) {
      return { ready: true };
    }
    
    return {
      ready: false,
      waitMs: current.retryAfter,
      currentTokens: current.value,
    };
  },
});

Notes

Unlike check(), which evaluates whether an action would be allowed, getValue() returns the raw state data. Use getValue() when you need to display quota information or perform custom calculations.
The value returned can be a decimal number for token bucket rate limits, as tokens accumulate gradually over time. Use Math.floor() if you need a whole number.
For rate limits that haven’t been used yet, getValue() will return the initial state with full capacity.
The ts field has different meanings depending on the rate limit type:
  • Token bucket: The last time tokens were calculated/updated
  • Fixed window: The start time of the current window