Skip to content

Rate limiting

How OpenQuok caps traffic so sign-in, your workspace, and public pages stay reliable.

5 min read

Connect your agent today

Draft from chat, review in your calendar, and publish only what you approve.

Start your free trial

Overview

Rate limiting means OpenQuok counts how many requests someone sends in a time window. A request can be from a signed-in user, an API key, or a visitor IP address.

When the count goes over the cap, the API returns 429 Too Many Requests. The person must wait until the window resets.

Limits protect sign-in, the dashboard, public blog and listing pages, uploads, and integrations. Messages from social networks (webhooks) are not rate limited. Those go server to server.

The table below shows typical production caps. You can change them with environment variables (see Environment variables).

Limits by area

Each row is one rule. One request matches one rule, not every rule at once.

AreaWho it applies toDefault cap (production)
Public blog, listings, and similar read pagesVisitors (by IP)600 requests per hour
Signed-in workspace APIYour account (by user id)2000 requests per hour
Other anonymous API callsVisitors (by IP)120 requests per hour
Sign-in and password routesBy IP50 requests per 15 minutes
OAuth sign-in (Google and similar)By IP20 requests per 5 minutes
Public API (API keys)Per key, or IP if no key30 requests per hour
MCP tools endpointToken or IP120 requests per hour
File uploadsToken or IP20 requests per hour
Feedback formBy IP10 requests per hour
Connect a social channelBy IP30 requests per 15 minutes
OAuth token exchange for appsBy IP30 requests per 15 minutes
Small public write actions (stats, activity)By IP60 requests per hour

Public read pages are not unlimited. The first row stops heavy scraping from overloading your server.

Visitor IP address

The API needs each visitor’s real IP to count fairly.

If Cloudflare sits in front of OpenQuok, set TRUST_CLOUDFLARE_HEADERS so the API sees the visitor IP, not one shared edge IP. Without that, many real users can look like one person and hit limits too soon.

Optional VERIFY_CLOUDFLARE_IP_RANGE only trusts that header when the request really came through Cloudflare.

Shared counters with Redis

In production, counters usually live in Redis when RATE_LIMIT_REDIS_ENABLED is on. Then every API server shares the same counts.

Redis uses the same host settings as cache (REDIS_HOST, REDIS_PORT). If Redis is off or unreachable at startup, each API instance keeps its own in-memory counts until Redis is available.

Public read routes also send cache headers. Browsers and CDNs can reuse responses for a short time. That lowers load and helps you stay under read limits.

Content typeTypical behavior
List and hub pages (indexes, categories, tags)Short public cache (about 1 minute)
Single pages you edit in secret-adminNo cache — fresh after save
RSS feedLonger cache (about 1 day)
Public imagesAbout 1 hour, with a longer stale window

The public website follows similar rules. For why more than one cache layer exists, see Cache design → Public content and caching.

Tune cache duration with PUBLIC_CMS_CACHE_ENABLED and PUBLIC_CMS_CACHE_*.

When something is blocked

Search API logs for Rate limit exceeded. Each line shows which rule fired, the IP, the path, and the cap.

If real users hit limits, raise the cap for that area (public read or signed-in session). Lower caps only when you see abuse.

Environment variables

Set RATE_LIMIT_ENABLED to false to turn off all limiters. Do not do this in production.

Copy backend/.env.development.example to backend/.env.development.local for sample values when you test locally:

# From repo root — example only; adjust values for your machine
cp backend/.env.development.example backend/.env.development.local
GroupWhat you change
Master switchRATE_LIMIT_ENABLED
Visitor IPTRUST_CLOUDFLARE_HEADERS, VERIFY_CLOUDFLARE_IP_RANGE
Public read pagesPUBLIC_READ_RATE_LIMIT_WINDOW_MS, PUBLIC_READ_RATE_LIMIT_MAX
Signed-in workspaceSESSION_RATE_LIMIT_WINDOW_MS, SESSION_RATE_LIMIT_MAX
Other anonymous APIRATE_LIMIT_WINDOW_MS, RATE_LIMIT_MAX
Sign-in and OAuthAUTH_RATE_LIMIT_*, OAUTH_RATE_LIMIT_*
Public API and MCPPUBLIC_API_RATE_LIMIT_*, MCP_RATE_LIMIT_*
Uploads and feedbackUPLOAD_RATE_LIMIT_*, FEEDBACK_RATE_LIMIT_*
Channel connect and app tokensINTEGRATION_CONNECT_RATE_LIMIT_*, OAUTH_TOKEN_RATE_LIMIT_*
Public writesPUBLIC_WRITE_RATE_LIMIT_*
Redis storeRATE_LIMIT_REDIS_ENABLED, RATE_LIMIT_REDIS_PREFIX, RATE_LIMIT_REDIS_DB
Public page cachePUBLIC_CMS_CACHE_ENABLED, PUBLIC_CMS_CACHE_MAX_AGE, PUBLIC_CMS_CACHE_STALE_WHILE_REVALIDATE, PUBLIC_CMS_RSS_CACHE_MAX_AGE, PUBLIC_CMS_IMAGE_CACHE_*

Example production-related values (full list is in the example env file):

RATE_LIMIT_ENABLED=true
RATE_LIMIT_REDIS_ENABLED=true
TRUST_CLOUDFLARE_HEADERS=true
PUBLIC_READ_RATE_LIMIT_MAX=600
SESSION_RATE_LIMIT_MAX=2000

Production checklist

Workers and the web app do not need these variables. See Production deployment.

Search documentation
Find a docs page
Discord Support