diff --git a/docs/guide/standalone/options.md b/docs/guide/standalone/options.md
index 85677e1d..5a7e4eca 100644
--- a/docs/guide/standalone/options.md
+++ b/docs/guide/standalone/options.md
@@ -45,6 +45,31 @@ If so, you can change the IP extraction logic to simply read from a header set i
The `/siteverify` endpoint is intended for server-to-server use, so it's not ratelimited by default.
+## Adaptive challenge count
+
+You can increase the number of proof-of-work challenges dynamically based on request frequency. This is configured per site key from the dashboard's **Configuration** tab under **Adaptive challenge count**.
+
+When enabled, you select a **time window** (1 minute to 1 hour) and define tiers at two levels:
+
+### Global tiers
+
+Increase the challenge count when the **total** number of challenge requests (across all IPs) exceeds a threshold within the time window. This is particularly effective against distributed attacks (botnets, proxy rotation) where each individual IP stays below per-IP limits.
+
+### Per-IP tiers
+
+Increase the challenge count when a **single IP** exceeds a request threshold within the time window. This targets repeat offenders without affecting legitimate users.
+
+When both global and per-IP tiers are configured, the **highest** resulting challenge count is used. The base challenge count (set in the **Main** section) is always the minimum.
+
+Example configuration:
+
+| Level | Min requests | Challenge count |
+|---------|-------------|-----------------|
+| Global | 100 | 150 |
+| Global | 500 | 300 |
+| Per-IP | 5 | 150 |
+| Per-IP | 15 | 300 |
+
## Redis / Valkey
Cap Standalone uses Redis (or Valkey) for all data storage. Set the `REDIS_URL` environment variable to your Redis connection string. This defaults to `redis://localhost:6379`.
diff --git a/standalone/public/assets/style.css b/standalone/public/assets/style.css
index aafd5a93..99b61fe3 100644
--- a/standalone/public/assets/style.css
+++ b/standalone/public/assets/style.css
@@ -2445,6 +2445,32 @@ input[type="range"]::-moz-range-progress {
opacity: 1;
}
+.adaptive-tier-row {
+ align-items: flex-end;
+}
+
+.adaptive-tier-row .origin-remove-btn {
+ margin-bottom: 8px;
+}
+
+.add-btn {
+ display: inline-flex;
+ align-items: center;
+ background: none;
+ border: 1px dashed var(--border);
+ color: var(--text-secondary);
+ font-size: 13px;
+ padding: 6px 12px;
+ border-radius: 6px;
+ cursor: pointer;
+ transition: all 0.15s;
+}
+
+.add-btn:hover {
+ border-color: var(--blue);
+ color: var(--blue);
+}
+
.header-checks {
display: flex;
flex-wrap: wrap;
diff --git a/standalone/public/js/dashboard.js b/standalone/public/js/dashboard.js
index e282aa22..6fc651c6 100644
--- a/standalone/public/js/dashboard.js
+++ b/standalone/public/js/dashboard.js
@@ -429,6 +429,65 @@ function renderKeyDetail() {
+
Adaptive challenge count
+
+
+
+
+
+
+
+
+
+
+
+
Global tiers
+
Increase challenge count when total requests across all IPs exceed the threshold. Useful against distributed attacks.