Skip to main content
The routes anyone can reach without signing in (sign-in, sign-up, password reset and one-time codes) are rate limited out of the box. Nothing needs configuring for that. This page is for tightening or loosening the limits, adding a captcha, and the other hourly caps.

Sign-in rate limits

Each protected action is counted twice over a rolling 15-minute window: once per email address and once per IP address. Whichever limit is reached first refuses further requests until the window moves on. The sign-in limits are loose on purpose: they stop credential stuffing and mail bombing, and an office behind one shared address should never reach them. With REDIS_URL set, as in every standard install, the counters live in Redis and are shared by every backend. Without Redis, each process counts on its own. The backend logs which at start, for example Abuse guard using Redis counters (shared across instances). If Redis becomes unreachable, requests are let through rather than locking everyone out.

Change the limits

Every number can be set. The variable is GUARD_ + the action’s name in capitals + _EMAIL or _IP:
GUARD_WINDOW_MS is the window in milliseconds. 0 turns off that count, so GUARD_LOGIN_IP=0 stops counting sign-ins per IP while still counting them per email.
A value that is not a whole number falls back to the default without a warning, so a typo keeps the old limit. Test a change rather than assume it took.

Add a captcha

Cloudflare Turnstile can be required before an action goes through. It is off until you set it up.
1

Create a Turnstile widget

In the Cloudflare dashboard, add a Turnstile widget for your domain. You get a site key and a secret key.
2

Set both keys

Set both. The site key alone shows the widget, but without the secret nothing checks the answer.
3

Choose the actions it guards

By default only otp_request asks for the captcha. List others by name, separated by commas:

Passwordless sign-in

People then sign in with a one-time code sent by email. It is compared against the exact string true, and it needs working email: without a provider the codes never arrive and nobody can sign in.

Public API and upload caps

Separate from the sign-in limits, two hourly caps apply per workspace: They are counted separately, so a folder of files added to the media library never uses up the posting cap. The other public API routes and posts made in the app are not counted. With Redis, the counts are shared by every backend. A request over the cap is answered with 429: see Limits and errors.

Farcaster signer routes

Connecting Farcaster uses two public routes: one creates a Neynar managed signer, the other checks whether the person approved it. Both are limited per client address, with numbers fixed in the code: The client address is the last entry of the X-Forwarded-For header, the one added by the nginx inside the container, so a client cannot choose its own count by sending the header. Behind a reverse proxy of your own, that last entry is the proxy’s address as the container sees it. Everyone then shares one count, which allows 30 new Farcaster connections per hour across the whole install.
Last modified on October 9, 2026