Korzen
Bot Protection

Bot detection API

Customers in, bots out

Before a login, a sign-up, a checkout or any page bots go after, your server asks Bot Protection about the visitor and gets back a class, a score and the reasons. No proxy in front of your site, no puzzles for your customers.

14-day free trial · plans from $29 a month

# Ask before the protected action
curl -X POST https://korzen.dev/v1/decide \
  -H "Authorization: Bearer $KORZEN_API_KEY" \
  -d '{
    "ip": "203.0.113.10",
    "user_agent": "Mozilla/5.0 …",
    "token": "<_kz cookie>",
    "path": "/checkout"
  }'
// Ask before the protected action; let through on any error
const d = await fetch(API + "/v1/decide", {
  method: "POST",
  headers: { Authorization: `Bearer ${KEY}` },
  body: JSON.stringify({ ip, user_agent, token, path }),
  signal: AbortSignal.timeout(200),
}).then((r) => r.json()).catch(() => null);

if (d?.action === "block") return res.status(403).end();
# Ask before the protected action; let through on any error
try:
    d = requests.post(API + "/v1/decide",
        headers={"Authorization": f"Bearer {KEY}"},
        json={"ip": ip, "user_agent": ua, "token": token},
        timeout=0.2).json()
except requests.RequestException:
    d = {}
if d.get("action") == "block":
    abort(403)
// Ask before the protected action; let through on any error
c := &http.Client{Timeout: 200 * time.Millisecond}
r, _ := http.NewRequest("POST", api+"/v1/decide", body)
r.Header.Set("Authorization", "Bearer "+key)
var d struct{ Action string }
if res, err := c.Do(r); err == nil {
    json.NewDecoder(res.Body).Decode(&d)
    res.Body.Close()
}
if d.Action == "block" {
    http.Error(w, "try again later", 403)
    return
}
// Ask before the protected action; let through on any error
var req = HttpRequest
    .newBuilder(URI.create(API + "/v1/decide"))
    .header("Authorization", "Bearer " + KEY)
    .timeout(Duration.ofMillis(200))
    .POST(BodyPublishers.ofString(json)).build();
String act = "";
try {
    var res = http.send(req, BodyHandlers.ofString());
    act = mapper.readTree(res.body())
        .path("action").asText();
} catch (Exception e) { /* let through */ }
if (act.equals("block")) {
    response.sendError(403);
    return;
}
// Ask before the protected action; let through on any error
$ch = curl_init(API . '/v1/decide');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode($visitor),
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . KEY],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT_MS => 200,
]);
$d = json_decode(curl_exec($ch) ?: '{}', true);
if (($d['action'] ?? '') === 'block') {
    http_response_code(403);
    exit;
}
// Ask before the protected action; let through on any error
// http: an HttpClient with "Authorization: Bearer KEY"
var act = "";
try {
    using var cts = new CancellationTokenSource(200);
    var res = await http.PostAsJsonAsync(
        Api + "/v1/decide", visitor, cts.Token);
    var d = await res.Content
        .ReadFromJsonAsync<JsonElement>(cts.Token);
    act = d.GetProperty("action").GetString();
} catch { /* let through */ }
if (act == "block") return Results.StatusCode(403);

200 OK RESPONSE

{
  "request_id": "AQEAmJ3…",
  "class": "bot_high",
  "bot_score": 96,
  "human_score": 0,
  "reasons": ["behaviour", "inconsistency"],
  "rules": [],
  "step_up": false,
  "action": "block",
  "intended_action": "block",
  "mode": "block",
  "challenge": null,
  "token_required": false,
  "seen_before": 0,
  "crawler": null
}
·:+* requests arriving | Bot Protection, before your action x a bot, stopped # a person, through

What it stops

The attacks Bot Protection is built for, at the step each one goes after.

Measured, not promised

Automation tools caught
15 of 15
Playwright with stealth flags, Chrome driven over CDP, curl_cffi posing as Chrome: our own tests, October 17, 2026
Answer time, p99
under 3 ms
at 600 decisions a second, measured at the server on 4 cores, the VM's shape, October 20, 2026
Default timeout
200 ms
past it, or on any error, your visitor goes through

The dashboard

See every decision, and why

The dashboard your team opens when traffic spikes: what Bot Protection answered, hour by hour, and the rules behind each answer.

Bot Protection · Overview
The overview: decisions per hour stacked by class, the share of bots, the top reasons and the latest bots

Every answer, with its reasons

The latest decisions, newest first, refreshed every few seconds. Filter by class, path, country, reason or time, and see each rule that fired. Hover a reason to read what it means.

Bot Protection · Decisions
The decisions table filtered by class, with time, class, bot score, path, country and reasons

How it works

Two pieces of code. No change to your traffic

1

Add the tag

A small script in your pages sends what the browser shows about itself straight to Bot Protection and keeps a signed token in a first-party cookie.

<script src="…/v1/tag.js"
  data-site-key="sk_…"
  async></script>
2

Ask before the action

Before a login, a sign-up, a checkout or any page bots go after, your server sends the request's IP, User-Agent and token, with a short timeout.

POST /v1/decide
{"ip": "…", "user_agent": "…",
 "token": "…",
 "path": "/checkout"}
3

Apply the action

Each answer says allow, challenge or block. You start in monitor mode, where it is always allow, and turn on block mode when you trust it. On any error or timeout, let the visitor through.

if d.Action == "block" {
    return http.StatusForbidden
}

Or paste one prompt into Claude Code, Codex or Cursor and let it add both: set up with AI.

Guides for Next.js, Express, Django, Rails, Laravel, Spring Boot, ASP.NET Core, Cloudflare Workers and more, in the docs.

The answer

A class you can act on, not a number to guess at

human high

A person, with proof from outside the session: a past order, their own card.

allow
human

A person your own feedback vouched for.

allow
unknown

Not enough evidence either way. Most first visits land here.

allow
bot

Automation, from what the client does.

challenge
bot high

Automation, with strong evidence of behaviour.

block

When strong evidence points both ways, the answer says step_up: ask for a passkey or 3-D Secure, not a CAPTCHA.

What Bot Protection reads

Evidence a bot cannot fake for long

Consistency

Does the User-Agent match the client hints, the platform, the Web Worker, the GPU? A patched browser contradicts itself.

Real input

Which kinds of input the page saw: mouse, keys, touch, wheel. Scripts click without ever moving.

The network

Datacenters, a time zone far from the IP, a round trip that betrays a proxy hop.

Farms

One device behind many networks, one token on many exits, one fingerprint across sessions: groups a farm cannot avoid.

Behaviour over time

Robotic cadence, retries through refusals, requests that never load a page. Ten minutes of memory per visitor.

Your feedback

Tell Bot Protection about a completed order or a chargeback. Proof from outside the session is what makes a visitor human.

Why an API

Protection without a new point of failure

Bot ProtectionCAPTCHAProxy in front of your site
Your visitors solve puzzlesNeverEvery timeSometimes
Your traffic goes through itNoNo, but every form waits on itAll of it
When it is downVisitors go throughForms stopYour site stops
Tells you whyThe class, the score and the kind of evidencePass or failA score
Where you decideIn your codeIn their widgetIn their rules

Questions

Before you ask

Will real customers be blocked?

Being on a VPN, a mobile network or a shared office connection can raise the score but never alone reaches bot. bot needs evidence of automation in what the client does. Customers who have bought from you before come back as human high.

Does Bot Protection store personal data?

Identifiers are hashed with a key per customer that rotates every day, so they cannot be joined across customers or days. Behaviour is forgotten after ten minutes; only counts and the latest decisions are kept for your dashboard.

Does a blocked bot still see my site?

Yes. Bot Protection judges the actions your server asks about, such as a sign-up, a login or a checkout, not page loads. A bot still loads your pages in block mode; what your server refuses is the action.

Your site, without the bots

Create an account, copy two snippets, and watch the decisions arrive.