Skip to main content
Version: 2026.1

Rate Limiting

The Studio Backend Bundle includes built-in rate limiting for all API endpoints to protect against abuse and ensure fair usage.

Overview

Rate limiting is enabled by default for all Studio API endpoints. Every request to a /pimcore-studio/api/ path is tracked using a sliding window algorithm, keyed by the client's IP address. When the limit is exceeded, the API responds with HTTP 429 Too Many Requests.

Additionally, specific public endpoints have their own stricter limits that apply on top of the general one.

Default Limits

LimiterScopePolicyLimitInterval
studio_api_generalAll Studio API endpointsSliding window500 requests1 minute
reset_passwordPOST /user/reset-passwordFixed window5 requests5 minutes
setting_admin_thumbnailGET /setting/admin/thumbnailFixed window60 requests1 minute

The per-endpoint limits are layered on top of the general limit. For example, the reset_password endpoint is subject to both its own 5/5min limit and the general 500/min limit.

Response Headers

Every Studio API response includes rate limit information in the following headers:

HeaderDescription
X-RateLimit-LimitMaximum number of requests allowed in the current window
X-RateLimit-RemainingNumber of requests remaining before the limit is reached
X-RateLimit-ResetUnix timestamp indicating when the current window resets

These headers are also included on 429 responses, so clients can determine when to retry.

Configuration

Disabling Rate Limiting

To disable the general rate limiter entirely, add the following to your project configuration:

# config/config.yaml
pimcore_studio_backend:
rate_limiting:
enabled: false

Customizing Limits

The rate limiters use Symfony's Rate Limiter component. You can override the defaults by redefining the limiter in your project's framework configuration:

# config/packages/framework.yaml
framework:
rate_limiter:
studio_api_general:
policy: 'sliding_window'
limit: 1000
interval: '1 minute'

Storage Backend

By default, Symfony stores rate limiter state in the cache.rate_limiter cache pool. In a multi-server deployment, you must use a shared cache backend (e.g., Redis or Memcached) to ensure rate limits are enforced consistently across all servers:

# config/packages/framework.yaml
framework:
cache:
pools:
cache.rate_limiter:
adapter: cache.adapter.redis

Without shared storage, each server tracks limits independently, effectively multiplying the allowed rate by the number of servers.

Deployment Considerations

Reverse Proxies and Load Balancers

Rate limiting is keyed by the client's IP address, obtained via Symfony's Request::getClientIp(). If your application runs behind a reverse proxy or load balancer, you must configure trusted proxies so that the real client IP is used instead of the proxy's IP:

# config/packages/framework.yaml
framework:
trusted_proxies: '127.0.0.1,REMOTE_ADDR'
trusted_headers: ['x-forwarded-for', 'x-forwarded-proto']

Without this configuration, all requests appear to come from the proxy's IP address, causing all users to share a single rate limit bucket.