Bot challenge
The bot challenge makes a visitor's browser solve a puzzle before a page of your website loads. A person waits once, and not again until the pass ends. A script that sends thousands of requests has to solve it over and over, and most scripts and simple bots can't solve it at all, because they don't run JavaScript. Their requests stop at the server's edge and never reach your website, so they cost you no PHP processes and no database queries.
Each gated path has a mode:
- Always: every visitor solves the challenge.
- Adaptive: every visitor gets in without one, and only a visitor that sends requests faster than people do is asked to solve it. Search engine crawlers get through.
It's the Bot challenge tab of a Website service: the paths it gates and their modes, the settings for them, who Adaptive lets through, and a reminder of what not to gate.
When to use it
For a page that programs hit in bulk:
- a contact or comment form that gets spam
- a login page that gets password guesses, e.g.
/wp-login.php - a search page requested so often that the site slows down
- an old script you can't change, such as a guestbook
It doesn't tell people from programs. A program that drives a real browser solves the puzzle the way a person's browser does; the challenge makes high-volume abuse slow and costly, not impossible. The server's rate limits still apply, before the challenge.
Always or Adaptive
A new rule starts as Adaptive once Adaptive challenges on your server, and as Always while it is in its trial period (below), so that a rule protects its path from the start. You can choose either when you add it. Rules made before Adaptive existed stay Always. Make Adaptive and Make Always in a rule's row switch it.
| Always | Adaptive | |
|---|---|---|
| Who solves the challenge | Every visitor, once per pass | Only a visitor that behaves like a bot |
| Search engines | Can't pass | Get through |
| Stops | Every program without a browser, however slow | Scrapers, crawlers that ignore robots.txt, password guessing and floods from a few addresses |
| Doesn't stop | A program that drives a real browser | The same, and a botnet that sends one request a minute from each of thousands of addresses |
| Use for | A form, a login page, a page under attack | A whole website (/) or a section, against scraping and load |
Adaptive counts each visitor's requests: by a cookie the server gives every browser, with no work and no page, or by address for a client that keeps no cookies. A visitor that goes over the server's limits, e.g. many page requests a minute, many form posts a minute, or many fresh cookies from one address, is flagged for one pass lifetime and solves the challenge on the Adaptive paths as on an Always path, with the same settings. The limits are the server's, not yours, and sit well above what a person reading pages does.
A form-spam network that posts once a minute from each of thousands of
addresses never goes over a limit. Gate a contact form, a comment form or
a login page with Always. The two modes combine: / Adaptive with
/contact.php Always works as it reads, because the longer path decides.
When the server first offers Adaptive, it only records which visitors it would challenge, so that its limits can be set from real traffic, and challenges nobody. The tab says so while it does. Adaptive paths aren't protected until a server update switches it on, so use Always where you need protection now; new rules start as Always until then.
The cookie Adaptive sets on HTML pages can stop a CDN in front of your website, such as Cloudflare, from caching those pages.
How a rule matches
A rule is a path prefix. It gates every request whose path starts with it,
on every name of the website: www., your aliases, and the subdomains of a
wildcard website.
A rule's mode applies to every request it gates. Where two rules match a request, the one with the longer path decides its mode.
| Rule | Gates | Doesn't gate |
|---|---|---|
/contact.php | /contact.php, /Contact.PHP, /contact.php/send | /contact.html |
/forms/ | /forms/, /forms/a.php, /forms/b/c.html | /forms (no trailing slash) |
/forms | /forms, /forms/, /forms.php, /formsx | /form |
/ | the whole website | /.well-known/ |
- Letter case doesn't matter.
- The server decodes a request's path before it compares, so
/contact%2ephpis/contact.php. You can paste a path from the address bar: the panel decodes it too. - Only the path is compared, not the part after
?. You can't gate/index.php?page=contactand leave/index.php?page=homeopen; if your application gives each page a path of its own, gate that path. /.well-known/is never gated, even under a rule for/, because certificate renewal and other automatic checks use it. The panel refuses a rule that starts with it.- A website can have up to 50 rules.
What not to gate
A rule gates an address, not a script: the server doesn't know which PHP file an address runs.
- One
index.phpfor every page: WordPress, Laravel and many other applications send each page throughindex.php, so a rule for/index.phpdoesn't gate/?s=spam. Gate the address the abuse goes to, e.g./wp-login.php,/wp-comments-post.phpor/search/. - A directory's index: a rule for
/forms/index.phpdoesn't gate/forms/, which shows the same page. Gate/forms/, which covers both; the tab suggests it next to a rule that ends in/index.php.
Some forms send their data in the background, to an address the visitor never opens. A visitor without a pass can't send such a form and gets an error. Gate the page with the form as well, or a prefix that covers both. A pass is good for every gated path on that host name, so the visitor solves the challenge once.
On an Always path, the server refuses every request they send. Don't gate an address used by these with Always:
- payment notifications and other webhooks
- mobile apps that use your website as an API
- uptime monitors
- feed readers
- search engines, which then leave the gated pages out of their results
On an Adaptive path a program at a polite rate isn't challenged, the search engines get through, and you can let your own monitors through by address. The server's own addresses are exempt, so a WordPress cron request still gets through, and so are any addresses your provider exempts.
Who Adaptive lets through
On Adaptive paths, some clients are never counted or challenged:
- On every website of the server: by default the search engines' crawlers (Googlebot, Bingbot, Applebot, DuckDuckBot and others), not the AI companies' crawlers. Your provider can change it.
- Added for this website: what you add under Who Adaptive lets
through on the tab. You can add a crawler kind (e.g. let AI
crawlers read this website), a crawler by name (e.g. only GPTBot), and
up to 50 addresses or networks of your own, e.g. an uptime monitor or a
partner's server (
192.0.2.10,198.51.100.0/24,2001:db8::/48).
A website can only add to the server's list, not take from it. A crawler is recognized by the addresses its operator publishes, never by the name it sends, which any scraper can copy. On Always paths nobody is let through but the server's own addresses and those your provider exempts.
Settings
The Settings card applies to every gated path of the website. Edit changes it.
| Setting | Values | Effect |
|---|---|---|
| Starting difficulty | Very low, Low, Medium (default), High, Very high | How much work a browser does for a visitor's first pass. It rises a little for a visitor who keeps using up passes or getting new ones. |
| Pass lasts | 1 hour, 12 hours (default), 24 hours | How long a visitor who solved the challenge gets through before the next one. |
| Requests per pass | 50 requests, 200 requests (default), 1,000 requests, Unlimited | How many requests one pass is good for. After the last one the visitor solves the challenge again, even if the pass's time hasn't run out. |
Raising the starting difficulty asks every visitor to solve the challenge again; lowering it doesn't. A new Pass lasts applies to the passes issued after the change, while a new Requests per pass applies to the passes visitors already hold.
Starting difficulty
The puzzle costs a person a wait and a bot computing time. The five difficulties go from the least work to the most, and each step up is several times the work of the one below it.
| Starting difficulty | Use for |
|---|---|
| Very low | Stopping scripts that don't run JavaScript, at almost no cost to anyone else |
| Low | Pages that people open often, e.g. a search page |
| Medium | Most pages |
| High | A form or a login page that keeps getting abuse at Medium |
| Very high | A page under attack. Visitors on phones and older computers can wait a long time. |
It's the difficulty a visitor starts at. A visitor's next challenge is one step harder when they:
- use up a pass's requests before the pass ends, or
- get more new passes within one Pass lasts period than the server allows. An address that many people share, such as an office network or a mobile network's IPv4 address, gets much more room than a single connection on IPv6.
The rise is short, only a little above the starting difficulty, and the server caps it. After one whole Pass lasts period without either, the visitor starts again at the starting difficulty. A bot that sends requests in bulk pays more for its passes, while a person who reads a few pages stays at the starting difficulty.
The passes a visitor already holds stay valid; only their next challenge is harder. That way a bot doesn't send everyone else behind the same address back to the challenge.
With Unlimited requests per pass, nothing is used up, so only getting many new passes makes the challenge harder.
The server sets how much work each difficulty is, and it can change with a
server update. To see the work of each step on your server and how long it
takes, open /.well-known/elpan/excuses/pow-benchmark/ on your website,
e.g. https://example.com/.well-known/elpan/excuses/pow-benchmark/, in the
browser of the device you want to know about. A phone is usually several
times slower than a desktop computer.
Requests per pass
A pass limited only by time would let a bot that solves the challenge once send requests for hours. With a limit, it pays for a new solve every 50, 200 or 1,000 requests, and the solves get harder, while a person reading a few pages never notices.
What counts:
- Only requests to gated paths. Pages outside your rules don't use up a pass.
- Not static files: images, style sheets, JavaScript files, fonts and other
files the server recognizes by their extension, e.g.
.css,.pngor.pdf. - Background requests do count when their address is gated: an editor's autosave, such as the WordPress editor's, and the AJAX requests a page sends while it's open.
For a busy admin area such as /wp-admin/, select 1,000 requests or
Unlimited. With a smaller number, someone who works there for a while
sees the challenge again.
What a visitor sees
A short page titled Checking your browser, with a progress bar. When the puzzle is solved, the browser loads the page the visitor asked for, without a click. Until the pass ends, every gated page on that host name then opens directly. A pass ends when its time runs out or its requests are used up.
- A form sent without a pass: the challenge page shows instead. When it's done, it doesn't reload by itself but asks the visitor to send the form again, with a Send again button. The browser may ask them to confirm.
- A new network: a pass only works from the address it was issued to (the IPv4 address, or the IPv6 /64). A phone that moves from Wi-Fi to mobile data solves the challenge again.
- Another name of the website: the browser keeps a pass per host name,
so going from
example.comtowww.example.commeans one more challenge. - Deleted cookies: the browser keeps its pass in a cookie. A visitor who deletes it solves the challenge again on the next gated page, and each of those passes counts toward the server's allowance, so starting over this way makes the challenge harder, not easier.
- No JavaScript: the visitor can't open a gated page. The challenge page tells them the check needs JavaScript.
The edge sends the challenge page with status 403, so each challenge is a 403 in your access log.
The server takes many 403 answers from one address in a short time as a sign of an attack. People in one office who open a gated page at the same moment all come from one address. If visitors from such a network report trouble, ask your provider.
From a script or the assistant
The REST API and the MCP server manage the same rules, modes, settings and exemptions, with the same checks as the tab, so the assistant can gate paths for you too. A refused path says why.