This TYPO3 extension provides a frontend middleware for rate limiting requests based on configurable rules.
In case your server or hoster cannot deal with Rate Limiting, but your
system is typically under heavy load, this extension is for you. It is based
on the symfony/rate-limiting component.
- IP-based rate limiting: Limit requests per IP address
- URL pattern filtering: Apply rate limiting only to specific URLs (e.g., search, forms)
- HTTP method filtering: Rate limit only specific HTTP methods (GET, POST, etc.)
- User-Agent filtering: Rate limit specific bots, crawlers, or API clients
- IP masking: Group requests by IP blocks (useful for proxies or shared IPs)
- Caching Framework storage: Uses TYPO3's Caching Framework for persistence
- Site-specific configuration: Configure different limits per TYPO3 site
- DB logging: Every blocked request is written to
tx_rate_limiting_log - Enrichment event: A PSR-14 event lets any extension add extra fields to the log entry
- Configurable 429 page: Uses the site's error handler for status 429 when configured
- Install the extension via TER or
composer req b13/rate-limiting - Activate the extension in the Extension Manager whe installed via TER.
- Configure via Site Settings (see Configuration section)
Configuration is done via Site Sets.
- Type: Boolean
- Default:
false - Description: Enable or disable rate limiting for this site
- Type: Integer
- Default:
100 - Description: Maximum number of requests allowed within the interval
- Type: String
- Default:
1 minute - Description: Time interval for the rate limit
- Examples:
30 seconds,1 minute,5 minutes,1 hour
- Type: Integer
- Default:
0(full IP) - Description: Number of IP blocks to use for grouping
- Examples:
0: Full IP (192.168.1.100)2: First 2 blocks (192.168.0.0)3: First 3 blocks (192.168.1.0)
- Type: String list
- Default:
[](all requests) - Description: Only rate limit requests matching these URL patterns
- Examples:
tx_solr: Rate limit Solr search requeststx_form: Rate limit form submissions/api/: Rate limit API endpoints
- Type: String list
- Default:
[](all methods) - Description: Only rate limit specific HTTP methods
- Examples:
POST,PUT,DELETE
- Type: String list
- Default:
[](all user agents) - Description: Only rate limit requests with matching User-Agent headers
- Supports: Simple string matching and wildcard patterns (
*and?) - Examples:
Googlebot: Rate limit Google's crawlerbot: Rate limit any user agent containing "bot"*crawler*: Wildcard matching for any crawlercurl*: Rate limit curl and similar toolsPython-*: Rate limit Python HTTP clients
settings:
rateLimiting:
enabled: true
limit: 50
interval: '1 minute'
urlPatterns:
- 'tx_solr'settings:
rateLimiting:
enabled: true
limit: 20
interval: '1 minute'
ipMaskLength: 2
methods:
- POSTsettings:
rateLimiting:
enabled: true
limit: 10
interval: '5 minutes'
urlPatterns:
- 'tx_form'
methods:
- POSTsettings:
rateLimiting:
enabled: true
limit: 30
interval: '1 minute'
userAgentPatterns:
- 'bot'
- 'crawler'
- 'spider'settings:
rateLimiting:
enabled: true
limit: 100
interval: '1 hour'
urlPatterns:
- '/api/'
userAgentPatterns:
- 'curl*'
- 'Python-*'
- 'PostmanRuntime*'DB logging is disabled by default. Enable it per site via the rateLimiting.logging setting:
settings:
rateLimiting:
enabled: true
logging: trueEvery request that hits the rate limit is then written to the tx_rate_limiting_log database table with
the following fields:
| Field | Description |
|---|---|
ip |
Remote IP address |
timestamp |
Unix timestamp of the blocked request |
time |
Human-readable datetime (Y-m-d H:i:s) |
domain |
Host from the request URI |
query |
JSON-encoded query parameters |
user_agent |
User-Agent header |
Log entries are automatically cleaned up after 90 days when TYPO3's Table garbage collection scheduler task is active.
Before writing to the database the middleware dispatches a
B13\RateLimiting\Event\RateLimitExceededEvent. Any event listener can call
addLogField(string $key, mixed $value) to inject additional columns into the
log record. The column must already exist in the table (add it via your
extension's ext_tables.sql).
Example: store the visitor's country
- Extend the table in your extension's
ext_tables.sql:
CREATE TABLE tx_rate_limiting_log (
country varchar(12) default '' not null
);- Register an event listener (TYPO3 13+):
<?php
declare(strict_types=1);
namespace Vendor\MyExtension\EventListener;
use B13\RateLimiting\Event\RateLimitExceededEvent;
use TYPO3\CMS\Core\Attribute\AsEventListener;
use TYPO3\CMS\Core\Http\NormalizedParams;
#[AsEventListener]
class EnrichRateLimitLogEntry
{
public function __invoke(RateLimitExceededEvent $event): void
{
$normalizedParams = $event->getRequest()->getAttribute('normalizedParams')
?? NormalizedParams::createFromRequest($event->getRequest());
// Resolve the country by whichever means fits your project, then:
$event->addLogField('country', $this->resolveCountry($normalizedParams->getRemoteAddress()));
}
private function resolveCountry(string $ip): string
{
// your geo-IP lookup here
return '';
}
}The listener is auto-registered through autoconfigure: true in Services.yaml and the
#[AsEventListener] attribute — no further configuration required.
By default the middleware returns a plain TYPO3 error page for HTML requests and a JSON response
for requests that send Accept: application/json.
To serve a fully styled error page, configure a Page error handler for HTTP status 429 in the site module. The middleware will automatically delegate to that handler when it is present.
The extension is licensed under GPL v2+, same as the TYPO3 Core. For details see the LICENSE file in this repository.
This extension was created by Benni Mack in 2025 for b13 GmbH, Stuttgart.
Find more TYPO3 extensions we have developed that help us deliver value in client projects. As part of our work, we focus on testing and best practices to ensure long-term performance, reliability, and results in all our code.