mirror of
https://github.com/formbricks/formbricks.git
synced 2026-05-24 11:39:31 -05:00
147 lines
10 KiB
Plaintext
147 lines
10 KiB
Plaintext
---
|
|
title: "Rate Limiting"
|
|
description: "Current request rate limits in Formbricks"
|
|
icon: "timer"
|
|
---
|
|
|
|
Formbricks applies request rate limits to protect against abuse and keep API usage fair.
|
|
|
|
Starting with Formbricks v5, rate limiting is split across two layers:
|
|
|
|
- Envoy Gateway for public and API-key routes that can be enforced at ingress
|
|
- The application server for remaining session-authenticated routes, server actions, and other flows Envoy does
|
|
not currently cover
|
|
|
|
<Warning>
|
|
Formbricks v5 removes application-level rate limiting for several routes that are now expected to be
|
|
protected by Envoy Gateway. If you self-host Formbricks without Envoy or an equivalent edge rate limiter,
|
|
those routes will no longer be throttled by the application server after upgrading.
|
|
</Warning>
|
|
|
|
<Info>
|
|
For the full self-hosted upgrade checklist, use this page together with the
|
|
[v5 migration guide](/self-hosting/advanced/migration#v5).
|
|
</Info>
|
|
|
|
Rate limits are scoped by identifier, depending on the endpoint and enforcement layer:
|
|
|
|
- IP hash (for unauthenticated/client-side routes and public actions)
|
|
- API key ID (for Envoy-managed and app-managed authenticated API calls)
|
|
- User ID (for authenticated session-based calls and server actions)
|
|
- Organization ID (for follow-up email dispatch)
|
|
|
|
When a limit is exceeded, the API returns `429 Too Many Requests`.
|
|
|
|
## v5 Migration Note
|
|
|
|
Before upgrading to Formbricks v5:
|
|
|
|
- deploy Envoy Gateway or an equivalent edge rate limiter for the covered routes below
|
|
- keep application Redis/Valkey enabled for the remaining app-enforced limits
|
|
- expect covered routes to emit gateway `429`s instead of the legacy app JSON `429`s
|
|
|
|
For the current source of truth on covered routes and thresholds, use this page together with your deployment
|
|
configuration and the [v5 migration guide](/self-hosting/advanced/migration#v5).
|
|
|
|
## Envoy-Managed Limits
|
|
|
|
These limits are expected to be enforced at the gateway layer in Formbricks v5 and later:
|
|
|
|
| **Route Group** | **Limit** | **Window** | **Identifier** |
|
|
| ------------------------------------------------------------------------ | ------------ | ---------- | -------------- |
|
|
| `POST /api/auth/callback/credentials` | 40 requests | 1 hour | IP hash |
|
|
| `POST /api/auth/callback/token` | 10 requests | 1 hour | IP hash |
|
|
| `GET, POST, PUT, PATCH, DELETE /api/v1/management/*` (API key auth only) | 100 requests | 1 minute | API key ID |
|
|
| `POST /api/v1/management/storage` (API key auth only) | 5 requests | 1 minute | API key ID |
|
|
| `GET, POST, PUT, PATCH, DELETE /api/v1/webhooks/*` (API key auth only) | 100 requests | 1 minute | API key ID |
|
|
| `GET /api/v1/client/[workspaceId]/environment` | 100 requests | 1 minute | IP hash |
|
|
| `POST /api/v1/client/[workspaceId]/responses` | 100 requests | 1 minute | IP hash |
|
|
| `PUT /api/v1/client/[workspaceId]/responses/[responseId]` | 100 requests | 1 minute | IP hash |
|
|
| `POST /api/v1/client/[workspaceId]/displays` | 100 requests | 1 minute | IP hash |
|
|
| `POST /api/v1/client/[workspaceId]/user` | 100 requests | 1 minute | IP hash |
|
|
| `POST /api/v1/client/[workspaceId]/storage` | 5 requests | 1 minute | IP hash |
|
|
| `POST /api/v2/client/[workspaceId]/responses` | 100 requests | 1 minute | IP hash |
|
|
| `PUT /api/v2/client/[workspaceId]/responses/[responseId]` | 100 requests | 1 minute | IP hash |
|
|
| `POST /api/v2/client/[workspaceId]/displays` | 100 requests | 1 minute | IP hash |
|
|
| `POST /api/v2/client/[workspaceId]/storage` | 5 requests | 1 minute | IP hash |
|
|
| `DELETE /storage/[workspaceId]/public/[fileName]` (API key auth only) | 5 requests | 1 minute | API key ID |
|
|
| `DELETE /storage/[workspaceId]/private/[fileName]` (API key auth only) | 5 requests | 1 minute | API key ID |
|
|
|
|
Session-authenticated `/api/v1/management/*`, `/api/v1/management/me`, `/api/v1/management/storage`, and
|
|
`DELETE /storage/...` requests are **not** covered by the current Envoy policies and remain app-enforced.
|
|
|
|
## App-Enforced Limits
|
|
|
|
These are the limits that still run inside the Formbricks application server:
|
|
|
|
| **Config** | **Limit** | **Window** | **Identifier** | **Used For** |
|
|
| ----------------------------- | ------------ | ---------- | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| `auth.signup` | 30 requests | 60 minutes | IP hash | Signup server action |
|
|
| `auth.forgotPassword` | 5 requests | 60 minutes | IP hash | Forgot password server action |
|
|
| `auth.verifyEmail` | 10 requests | 60 minutes | IP hash | Resend verification server action |
|
|
| `api.v1` | 100 requests | 1 minute | Session user ID | Session-authenticated v1 management routes, `/api/v1/management/me`, and `/api/v1/integrations/*` |
|
|
| `api.v2` | 100 requests | 1 minute | API key ID | Authenticated v2 API wrapper outside the Envoy-managed `/api/v2/client/*` subset |
|
|
| `api.v3` | 100 requests | 1 minute | API key ID or session user ID | v3 API wrapper |
|
|
| `api.client` | 100 requests | 1 minute | IP hash | Uncovered client routes such as `GET /api/v1/client/og`, `GET /api/v2/client/[workspaceId]/environment`, and `POST /api/v2/client/[workspaceId]/user` |
|
|
| `storage.upload` | 5 requests | 1 minute | Session user ID | Session-authenticated `POST /api/v1/management/storage` |
|
|
| `storage.delete` | 5 requests | 1 minute | Session user ID | Session-authenticated `DELETE /storage/[workspaceId]/[accessType]/[fileName]` |
|
|
| `actions.emailUpdate` | 3 requests | 60 minutes | User ID | Profile email update action |
|
|
| `actions.surveyFollowUp` | 50 requests | 60 minutes | Organization ID | Survey follow-up email processing |
|
|
| `actions.sendLinkSurveyEmail` | 10 requests | 60 minutes | IP hash | Link survey email send action |
|
|
| `actions.licenseRecheck` | 5 requests | 1 minute | User ID | Enterprise license recheck action |
|
|
|
|
## Explicit Envoy Exclusions
|
|
|
|
The current Envoy policy set explicitly excludes these routes:
|
|
|
|
- `GET /api/v1/client/og` (still covered by the app-level `api.client` limiter)
|
|
- `GET /api/v2/health` (not rate-limited)
|
|
- `OPTIONS` requests (not rate-limited)
|
|
|
|
## 429 Response Shape
|
|
|
|
Application-generated v1 `429`s return:
|
|
|
|
```json
|
|
{
|
|
"code": "too_many_requests",
|
|
"details": {},
|
|
"message": "Maximum number of requests reached. Please try again later."
|
|
}
|
|
```
|
|
|
|
Application-generated v2/v3 `429`s return:
|
|
|
|
```json
|
|
{
|
|
"error": {
|
|
"code": 429,
|
|
"message": "Too Many Requests"
|
|
}
|
|
}
|
|
```
|
|
|
|
Envoy-generated `429`s are gateway responses and should include an `x-envoy-ratelimited` header. Their exact body
|
|
shape is not the same stability contract as the in-app JSON responses above.
|
|
|
|
## Disabling Rate Limiting
|
|
|
|
For self-hosters, rate limiting can be disabled if necessary. We strongly recommend keeping it enabled in production.
|
|
|
|
Set:
|
|
|
|
```bash
|
|
RATE_LIMITING_DISABLED=1
|
|
```
|
|
|
|
After changing this value, restart the server.
|
|
|
|
This setting disables only the **application-level** limiter. It does **not** disable Envoy rate-limit policies.
|
|
|
|
## Operational Notes
|
|
|
|
- Redis/Valkey is required for the application-level limiter (`REDIS_URL`).
|
|
- If you deploy Envoy rate limiting, use a dedicated Redis/Valkey backend for Envoy instead of sharing the app cache.
|
|
- If application Redis is unavailable at runtime, app rate-limiter checks currently fail open (requests are allowed through without enforcement).
|
|
- Authentication failure audit logging uses a separate throttle (`shouldLogAuthFailure()`) and is intentionally **fail-closed**: when Redis is unavailable or errors occur, audit log entries are **skipped entirely** rather than written without throttle control. This prevents spam while preserving the hash-integrity chain required for compliance. In other words, if Redis is down, no authentication-failure audit logs will be recorded—requests themselves are still allowed (fail-open rate limiting above), but the audit trail for those failures will not be written.
|