Sometimes you need to check if a rate limit would allow a request without actually consuming any tokens. The Convex Rate Limiter provides two methods for this:
check() - Check if a request would be allowed
getValue() - Get the current token count and metadata
The check() method evaluates a rate limit without consuming any tokens:
const status = await rateLimiter.check(ctx, "sendMessage", { key: userId});if (status.ok) { // The user has capacity available // But we haven't consumed any tokens yet}
From src/client/index.ts:78-111:
/** * Check a rate limit. * This function will check the rate limit and return whether the request is * allowed, and if not, when it could be retried. * Unlike {@link limit}, this function does not consume any tokens. * * @param ctx The ctx object from a query or mutation, including runQuery. * @param name The name of the rate limit. * @param options The rate limit arguments. * @returns `{ ok, retryAfter }`: `ok` is true if the rate limit is not exceeded. * `retryAfter` is the duration in milliseconds when retrying could succeed. */async check<Name extends string = keyof Limits & string>( ctx: RunQueryCtx, name: Name, ...options): Promise<RateLimitReturns> { return ctx.runQuery(this.component.lib.checkRateLimit, { ...options[0], name, config: this.getConfig(options[0], name), });}
const status = await rateLimiter.limit(ctx, "sendMessage", { key: userId });// ✅ Returns { ok, retryAfter }// ⚠️ CONSUMES a token if ok is true// ⚠️ Must be called in a MUTATION
/** * Get the current value and metadata of a rate limit. * This function returns the current token utilization data without consuming any tokens. * * @param ctx The ctx object from a query, including runQuery. * @param name The name of the rate limit. * @param options The rate limit arguments. * @returns An object containing the current value, timestamp, window start time (for fixed window), * and the rate limit configuration. */async getValue<Name extends string = keyof Limits & string>( ctx: RunQueryCtx, name: Name, ...options): Promise<GetValueReturns> { return ctx.runQuery(this.component.lib.getValue, { ...options[0], name, config: this.getConfig(options[0], name), });}
type GetValueReturns = { config: RateLimitConfig; // The rate limit configuration value: number; // Current token count ts: number; // Timestamp when last updated // For fixed window: windowStart?: number; // When the current window started};
You can check if there’s enough capacity for a specific count:
// Check if we have capacity for 100 tokensconst status = await rateLimiter.check(ctx, "llmTokens", { key: userId, count: 100,});if (status.ok) { // We have enough capacity for 100 tokens // But we haven't consumed them yet}