Core Concepts
Introduction
NiceTryBot has a small number of moving parts, and once you understand how they fit together, the rest of the control panel will feel familiar. In short: the edge sees every request, Activity shows you what it saw, rules decide who is up to no good, tags and bans record those decisions, and the bot gym gives the guilty something to do.
The Edge
The edge is NiceTryBot's front door. It is a build of Caddy that terminates TLS for every domain you protect, records each request, and decides where it should go.
Along with the usual details, such as the path, status, and user agent, the edge records how each visitor connected: its JA3 and JA4 TLS fingerprints, a JA4H fingerprint of its headers, its client hints, and its Accept-Language header. It also looks up the visitor's network and approximate location using local databases, so nothing is sent to a third party.
The edge also handles a few chores on its own. It tags requests for paths that only scanners ask for, such as .env, .git, and wp-admin. It introduces itself as nginx, with nginx-style error pages, so nothing a visitor sees names NiceTryBot. And WebSockets pass straight through.
How Requests Flow
When a request arrives, the edge checks it against your rules and the domain's protection mode:
- Humans always continue to your origin.
- Tagged visitors on a domain in Observe mode continue to your origin as well, but are marked in Activity so you can see what NiceTryBot would have done.
- Tagged visitors on a domain in Enforce mode are sent to the bot gym or blocked.
If the edge can't reach the control panel for any reason, it fails open and sends everyone to your origin.
Clients and Fingerprints
NiceTryBot thinks about visitors as clients. A client is an IP address together with its JA4 TLS fingerprint. Many people share a browser build, so many people share a JA4 fingerprint, but the fingerprint describes the software that actually connected, which is very hard for a script to fake.
When a client's details don't add up, NiceTryBot gives it a trait:
| Trait | Description |
|---|---|
spoofed |
Its user agent or client hints disagree with how it connected, such as a user agent claiming to be Chrome from a client whose TLS handshake isn't Chrome's. |
outdated |
Its browser is several versions behind the current release. |
corporate |
It appears to be behind a corporate security gateway. |
hopped |
It took over another IP address's visit. |
NiceTryBot also refreshes the published IP ranges of well-known crawlers every day, so a real crawler can be told apart from an impostor borrowing its name.
Activity
Activity is a live, filterable log of every request that reached the edge, what it asked for, and what NiceTryBot did about it. You may search it using the same WHERE syntax as rules, save searches you use often, and follow new requests as they arrive.
You may also label a client. Labels give a name to an IP address, fingerprint, user agent, or set of client hints, such as "office" or "uptime monitor", and appear everywhere that client does.
Request Actions
Each request in Activity shows the action the edge took:
| Action | Description |
|---|---|
| Passed | The request went to your origin. |
| Observed | The request was tagged, but went to your origin because its domain is in Observe mode. |
| In the gym | The request was sent to the bot gym. |
| Blocked | The request was refused. |
Analytics and 404s
Analytics shows who is knocking: the networks, countries, user agents, and TLS fingerprints behind your traffic, along with a flow diagram of where requests went and a live map. 404s shows which domains get the most "not found" responses, what was asked for, and whether it was a person or a probe. Scanners tend to ask for the same handful of paths, so this page is often the quickest way to spot them.
Rules
Rules decide which clients deserve attention. They are written in NiceTryBot's rule language, which reads like SQL but isn't SQL. Every rule either tags or bans the clients it matches, for as long as you specify.
Enabled rules run every minute over newly arrived requests. Single-request rules are also judged at the edge as requests arrive. You will find a gallery of ready-made rules on the Rules page, and the free Rule packs add-on includes more.
Writing Rules
A rule names an action, the subjects it applies to, a duration, and the requests it matches. For example, the following rule bans any IP address and fingerprint that goes fishing for secrets, admin panels, or exploits:
-- Anyone fishing for secrets, admin panels or exploits.
BAN ip, ja4 FOR 30 DAYS
WHERE category = 'probe'
A rule may tag clients instead of banning them. Tags are named using AS, and are a great way to mark clients you would like to send to the gym rather than refuse:
-- Claims to be Chrome or Firefox, but its TLS offers no ALPN: a script.
TAG ip, ja4 AS 'ua-tls-mismatch' FOR 1 DAY
WHERE (ua LIKE '%Chrome/%' OR ua LIKE '%Firefox/%')
AND ja4.alpn = '00'
Keywords are case-insensitive. Strings use single quotes, LIKE ignores case and supports the % and _ wildcards, and -- starts a comment. AND binds more tightly than OR, so use parentheses when combining them. Durations may use SECOND, MINUTE, HOUR, DAY, or WEEK, or FOREVER.
Counting Over Time
Using WITHIN and HAVING, a rule may count a client's requests over a window of up to 24 hours. For example, the following rule bans an IP address that collects 404 responses across several of your sites:
-- One IP collecting 404s across several of your sites.
BAN ip FOR 1 HOUR
WHERE status = 404
WITHIN 10 MINUTES
HAVING COUNT(*) >= 2 AND COUNT(DISTINCT host) >= 2
Similarly, this rule bans a flood of requests from a cloud or hosting network:
-- A flood of requests from a cloud or hosting network.
BAN ip, ja4 FOR 6 HOURS
WHERE network.kind = 'hosting'
WITHIN 5 MINUTES
HAVING COUNT(*) >= 60
You may also end a verdict early using UNTIL, followed by a condition. The complete grammar of the rule language is as follows:
script := action subjects [AS 'tag'] FOR duration [WHERE expr] [WITHIN span HAVING having] [UNTIL expr]
action := BAN | TAG
subjects := subject {, subject} subject := ip | ja4
duration := number unit | FOREVER span := number unit
unit := SECOND | MINUTE | HOUR | DAY | WEEK, or the plural
expr := term {OR term} term := factor {AND factor}
factor := NOT factor | ( expr ) | field predicate
predicate := op literal | [NOT] LIKE 'pattern' | [NOT] IN (literal, …) | IS [NOT] NULL
op := = | != | < | <= | > | >=
having := hterm {OR hterm} hterm := hfactor {AND hfactor}
hfactor := NOT hfactor | ( having ) | COUNT ( * | DISTINCT field ) [FILTER ( WHERE expr )] op number
Available Fields
Rules and Activity searches may use the following fields. Add-ons may add more.
| Field | Description |
|---|---|
ip |
The client's IP address. Accepts CIDR ranges, such as '66.249.64.0/19'. |
ja4 |
The client's JA4 TLS fingerprint. |
ja4.alpn |
The ALPN the client offered. '00' means none: a script, not a browser. |
ja3 |
The client's JA3 TLS fingerprint. |
ja4h |
The client's header fingerprint. |
ua |
The user agent. |
hints |
The client hints, such as LIKE '%HeadlessChrome%'. |
client |
The client's trait: 'spoofed', 'outdated', 'corporate', or 'hopped'. |
lang |
The Accept-Language header. A missing value is a tell-tale sign of a script. |
host |
The domain requested. |
path |
The path requested. |
category |
The path's category: a family like 'probe', or a slug like 'probe/creds'. |
status |
The response status, such as 404. |
method |
The request method, such as GET or POST. |
duration |
The response time, in milliseconds. |
action |
The edge's action: 'passed', 'observed', 'diverted', or 'blocked'. |
tag |
The edge's tag, such as 'probe'. |
asn |
The network's autonomous system number. |
network |
The network's name. |
network.kind |
The kind of network. 'hosting' covers cloud and datacenter networks. |
country |
The country, as an ISO 3166 code such as 'NL'. |
region |
The region. |
city |
The city. |
Testing Rules
Every rule is tested against your real traffic before it runs. When you write or edit a rule, NiceTryBot backtests it against past requests and shows you exactly which clients it would have caught. If the list includes your own office, you'll know before anyone gets banned.
Tags and Bans
When a rule matches a client, it reaches a verdict: a tag or a ban, along with when it first and last matched and when it expires. The Tags & bans page lists every client your rules have marked. You may lift a verdict at any time to let the client go immediately, although the rule may tag it again if it keeps matching.
Verdicts on their own don't block anyone. A ban is enforced on domains in Enforce mode, and a tag is something you can act on, most often by sending tagged clients to the bot gym. Ended verdicts are kept for 30 days.
The Bot Gym
Instead of refusing a suspicious visitor outright, you may send it to the bot gym. The gym puts visitors through obstacles that cost a bot CPU time and patience, but only cost a person a moment. The gym is served in place, at the address the visitor asked for, so its address bar never changes.
The gym only holds visitors on domains in Enforce mode.
Routines
A routine describes who goes to the gym and what they do there. Each routine has entry conditions, an ordered list of obstacles, an exit, and a pass time. Entry conditions may match a visitor's network, country, browser, user agent, IP address, TLS fingerprint, domain, path category, path, edge tag, or a rule's verdict.
When a visitor matches several routines, their obstacles stack into one pipeline and the strictest exit wins. Once a visitor completes the gym, they receive a pass that lasts for the routine's pass time, which may be anywhere from one minute to one week.
You may also send a rule's clients straight to the gym using the Send its clients to the gym option when editing a rule.
Obstacles
NiceTryBot includes the following obstacles:
| Obstacle | Description |
|---|---|
| Proof of work | The browser solves a SHA-256 puzzle in the background. People just wait a moment. |
| Waiting room | A queue that keeps the visitor's CPU busy, one proof of work after another, for as long as you set. |
| Type the code | A short code drawn as a noisy image. The visitor reads it and types it back. |
| Browser check | A silent look for automation, such as webdriver flags, headless windows, and a missing Chrome runtime. |
Add-ons may add more obstacles. For example, the Captchas add-on adds a set of puzzles people solve in a second and bots get lost in.
Exits
After the last obstacle, a routine's exit decides what happens next:
| Exit | Description |
|---|---|
| Continue to their page | The visitor gets a pass and lands where they were going. |
| Show a not-found page | The gym answers with a 404 itself. Your origin never sees the request. |
| Turn them away | The gym answers with a 403. |
Connecting an Agent
NiceTryBot's control panel includes an MCP server, so agents like Claude Code, Codex, and Cursor can read your traffic, add domains, write rules, and build gym routines on your behalf. The same tools are available from your terminal using the nicetrybot command. The MCP Server documentation covers API tokens, connecting an agent, and every tool the server offers.
Searching in Plain English
If you add an Anthropic API key in Settings → Artificial Intelligence, you may search Activity in plain English, such as "phones from the Netherlands that hit the login page yesterday". This feature is off until you add a key. It is the only feature that sends anything outside of your servers: your question, the search or rule you are editing, and your team's hostnames are sent to Anthropic using your own key.