A single HTTP call scores each request in real time. Block known bots, review risky traffic, and safeguard pricing, signup, and checkout without any pixels or SDKs.
If you spend $100k/month on acquisition and conservatively block 15% invalid traffic pre-click or pre-request, that’s about $15,000/month in avoided waste plus cleaner optimization signals.
We read the signals every request already carries: headers, user-agent integrity, client hints and origin. No pixels, no SDK. One HTTP call in, a clear decision out.
Block traffic from known data centers, VPNs, open proxies-and the hard part: residential proxy networks used to mimic “real” users.
A purpose-built model scores risk alongside continuously refreshed IP & crawler datasets. You get precision now and it gets smarter over time.
We don’t challenge your users. Challenge pages slow funnels and frustrate buyers. Cloudflare reported users spent ~32s on legacy challenges vs ~1s on their improved flow; the point stands: every second hurts conversion. Source: WIRED on CAPTCHA burden
Third-party scripts are a top cause of slow pages and unstable Core Web Vitals. We work server-to-server. No snippet to ship, no bundle to grow, no layout shift to explain to sales. Source: web.dev — Third-party JS guidance
Browsers now block cross-site tracking and known trackers by default, breaking pixels and many client-side detections. Our server-side API isn’t affected by ITP/ETP or ad-blockers. Sources: WebKit — Full third-party cookie blocking, Mozilla — Enhanced Tracking Protection
Start free. Upgrade when volume rises.
After checkout, you’ll see your API key (afk_…
) once. Send it as X-API-Key
with every
request.
Use /probe
to decide whether the current request looks robotic
Try it via curl
:
curl -s -H "X-API-Key: afk_xxx..." https://nobotspls.com/probe
You can override auto-detected values using query parameters.
curl -sG "https://nobotspls.com/probe" \
--data-urlencode "useragent=Mozilla/5.0 (Macintosh) Safari/605.1.15" \
--data-urlencode "ip=203.0.xxx.xx" \
--data-urlencode "headerorder=host, user-agent, accept" \
-H "X-API-Key: afk_xxx..."
See field definitions below in the HTTP API Doc
Check out the OpenAPI documentation Here.
Header | Required | Description |
---|---|---|
X-API-Key |
Yes | Your API key (format afk_… ). |
Content-Type |
Yes | application/json |
Single request (/score
):
{
"useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Safari/605.1.15",
"sec_ch_ua": "\"Chromium\";v=\"123\", \"Not A;Brand\";v=\"99\"",
"headerorder": "host, user-agent, accept, accept-encoding, accept-language",
"ip": "127.0.0.1",
"xforwardedfor": "104.21.32.1",
"extra_headers": { "cf-connecting-ip": "104.21.32.1" }
}
Batch request (/batch_score
):
[
{ "useragent": "Mozilla/5.0 …", "ip": "198.51.100.120", "headerorder": "host, user-agent, accept" },
{ "useragent": "curl/8.4.0", "ip": "203.0.113.42", "headerorder": "host, user-agent" }
]
Status | Meaning | Notes |
---|---|---|
200 |
OK | Score computed. |
400 |
Bad Request | Invalid or missing fields. |
401 |
Unauthorized | Missing/invalid X-API-Key . |
429 |
Rate limited | Free: 10 req/min, 500/day. Pro: 3000 req/min, 250k/day. |
5xx |
Server error | Retry with backoff. |
Notes: probabilities are calibrated to [0,1]
; your enforcement can use the
provided decision
or a custom threshold.
Provide as many headers as you naturally have. No client SDK is required.
Optionally provide API_KEY
with your key (afk_…
).
Call /probe
; we infer headers/IP from the request and return a decision. You can override any field via query params.
For more integrations like Wordpress, Nginx or Cloudflare check out the Github Repos.
# pip install requests
import requests
BASE = "http://nobotspls.com"
API_KEY = "afk_xxx..." # your API key (optional)
# Optional: override auto-detected values via query params
params = {
# "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Safari/605.1.15",
# "ip": "x.x.x.x",
# "headerorder": "host, user-agent, accept"
}
r = requests.get(f"{BASE}/probe",
headers={"X-API-Key": API_KEY},
params=params,
timeout=10)
print(r.status_code, r.json())
# customer_fastapi_example.py
import os
from fastapi import FastAPI, Request, HTTPException, Depends
import httpx
API_BASE = os.getenv("AF_API_BASE", "https://nobotspls.com")
API_KEY = os.getenv("AF_API_KEY", "afk_xxx...")
app = FastAPI()
async def bot_guard(request: Request):
headerorder = ", ".join(
k.decode("latin1").lower()
for k, _ in request.scope.get("headers", [])
)
h = request.headers
ip = ((request.client.host if request.client else "") or "").split(",")[0].strip()
# Override any values you want the upstream to consider
params = {
"useragent": h.get("user-agent", ""),
"sec_ch_ua": h.get("sec-ch-ua", ""),
"acceptlanguage": h.get("accept-language", ""),
"acceptencoding": h.get("accept-encoding", ""),
"accept": h.get("accept", ""),
"headerorder": headerorder,
"ip": ip,
}
try:
async with httpx.AsyncClient(timeout=5) as client:
res = await client.get(
f"{API_BASE}/probe",
headers={"X-API-Key": API_KEY},
params=params,
)
except httpx.RequestError as e:
raise HTTPException(status_code=502, detail=f"Bot check upstream error: {e!s}")
if res.status_code >= 400:
raise HTTPException(status_code=502, detail=res.text)
verdict = (res.json() or {}).get("decision", "allow")
if verdict == "block":
raise HTTPException(status_code=403, detail="Blocked by bot detection")
@app.post("/signup", dependencies=[Depends(bot_guard)])
async def signup():
return {"ok": True}
@app.get("/pricing")
async def pricing(_: None = Depends(bot_guard)):
return {"plan": "free"}
// Node 18+ (native fetch)
const BASE = "http://nobotspls.com";
const API_KEY = "afk_xxx...";
// Optional: add overrides as query params
const params = new URLSearchParams({
// useragent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Safari/605.1.15",
// ip: "x.x.x.x",
// headerorder: "host, user-agent, accept"
});
fetch(`${BASE}/probe?${params.toString()}`, {
method: "GET",
headers: { "X-API-Key": API_KEY }
})
.then(async (res) => console.log(res.status, await res.json()))
.catch(console.error);
export default {
async fetch(request, env) {
const h = request.headers;
const ip = (h.get("x-forwarded-for") || h.get("cf-connecting-ip") || "").split(",")[0].trim();
const params = new URLSearchParams({
useragent: h.get("user-agent") || "",
ip
// Add more overrides if desired, e.g. sec_ch_ua, acceptlanguage, headerorder, ...
});
const resp = await fetch("http://nobotspls.com/probe?" + params.toString(), {
method: "GET",
headers: { "X-API-Key": env.AFK_API_KEY }
});
return new Response(await resp.text(), { status: resp.status });
}
};