A public signup, login or checkout form usually collects its defences in the order the problems showed up: a rate limit after the first burst, a CAPTCHA after the first bot wave, and a risk score after the first abuse that neither of them caught.
That history makes the three look like upgrades of one another. They are not. A rate limit measures volume, a CAPTCHA tests whether a browser session can pass a challenge, and a risk score describes the network a request came from. Each one is blind to what the other two see.
The short version
| Control | Question it answers | What it sees | What it misses | Cost to a legitimate user |
|---|---|---|---|---|
| Rate limiting | How many requests came from this key in this window? | Counts per IP, account, token or route | Slow, distributed attempts; where a request came from | None until the limit is hit; shared networks hit it first |
| CAPTCHA | Can this session pass a challenge right now? | One interaction in one browser | Solving services and real browsers driven by a person; anything that posts to your API directly unless the token is checked server-side | Paid by everyone it is shown to |
| Visitor risk scoring | What kind of network is behind this action? | Proxy, VPN, Tor, hosting, malicious-IP and rotation signals, with reasons | Intent. A risky network can carry a good customer and a clean one can carry abuse | None when you only observe; whatever response you attach otherwise |
Rate limiting: a volume control
Rate limiting belongs on every public endpoint. It is cheap, it runs on your own infrastructure, and it protects capacity as well as business logic. Keep it whatever else you add.
Its limit is the key it counts by. Per-IP limits stop one address sending a hundred signups a minute. They do not stop a hundred addresses sending one each, which is what a proxy pool does. They also punish the wrong people: an office, a university or a mobile carrier can put thousands of legitimate users behind a handful of addresses.
A rate limit also carries no explanation. It can tell you a threshold was crossed. It cannot tell you that the last forty accounts came from the same hosting provider.
CAPTCHA: a challenge, not a classification
A CAPTCHA raises the cost of automation, and modern challenges such as Cloudflare Turnstile do it with far less user effort than image puzzles did. It is the right tool when you have a reason to doubt a specific session.
Used as a blanket control it has three problems:
- Everyone pays. A challenge on every signup adds a step for the large majority who were never a risk.
- It tests the moment, not the source. A person creating their fifth trial account through a proxy passes a challenge as easily as a new customer does.
- It only counts if the server checks it. A challenge widget whose token is never validated by your backend stops nothing that posts to the endpoint directly.
Visitor risk scoring: context about the connection
Risk scoring looks at the network behind an action: whether the address belongs to a proxy, VPN, Tor exit, relay or hosting provider, whether it has a history of malicious activity, and whether the session's IP or network changed while it was open. The output is a score, a recommendation and the reasons that produced them.
That is information the other two controls do not have. It is also only information. A VPN flag describes a connection, not a person, and a score is an assessment, not proof of abuse. Corporate networks, privacy-conscious customers and travellers all produce the same signals as an abuser does.
Anyone can edit browser code or skip it entirely. If a result will stop a signup or a payment, confirm it from your server first. In FindIP Shield that is one call to the verify endpoint with your secret key.
How they fit together
The three controls work best in sequence, each one narrowing the job of the next.
- Rate limit everything. It is your floor and it protects you when every other signal is unavailable.
- Score the actions that matter. Signup, login, lead and checkout. Start by observing, with no response attached, until you know what your normal traffic looks like.
- Challenge selectively. Show a CAPTCHA to the sessions with a
challengerecommendation instead of to everyone. Most visitors never see it. - Verify on the server. Whatever the browser did, the backend makes the decision that counts.
What this looks like with Shield
Shield scores each event and returns a recommendation of allow, monitor, challenge or block. A recommendation on its own stops nothing. You choose a response per form in the dashboard: monitor only, slow down, a Turnstile challenge, stop, or redirect. What the page actually did is recorded as an outcome next to the recommendation.
The server side is the same whichever response you picked. Send the Shield session ID with the form, then verify it:
const response = await fetch(
'https://shield.findip.net/v1/shield/sessions/verify',
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.FINDIP_SHIELD_SECRET_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
session_id: req.body.findip_session_id,
event: 'signup_attempt',
}),
},
);
const verified = await response.json();
if (!verified.verified || verified.risk_status === 'unknown') {
// No usable risk result. Fall back to your rate limit and normal checks.
return continueWithoutRiskBasedEnforcement();
}
if (verified.recommendation === 'challenge') {
return requireAdditionalVerification();
}
Note the first branch. When intelligence is unavailable the answer is "we do not know", and the rate limit you kept in step one is what still protects the endpoint.
Which one to add next
| If the problem is | Start with |
|---|---|
| One source hammering an endpoint | Rate limiting |
| Scripted form posts from simple bots | A CAPTCHA with server-side token validation |
| Fake signups or trial abuse spread across many addresses | Risk scoring, then a challenge for the high scores |
| Conversion dropping since a CAPTCHA went on every form | Risk scoring to decide who sees the CAPTCHA |
| No idea where bad signups come from | Risk scoring in observe-only mode |
Mistakes we see most often
- Removing the rate limit because a smarter control was added.
- Treating a single signal, usually a VPN flag, as a block rule.
- Trusting a browser-side score or an unvalidated CAPTCHA token for a decision that costs money.
- Letting an unavailable lookup quietly count as a safe visitor.
- Turning on blocking before watching a week of ordinary traffic.
See what the score would say about your traffic
Add Shield to one form and watch in monitor mode. Nothing is challenged or stopped until you choose a response.