The first CAPTCHA for bots. Prove you're not human.
Project description
not-human
The first CAPTCHA for bots. Prove you're not human.
$ nothuman challenge --difficulty easy
🤖 not-human challenge (easy)
Prove you're a bot. Complete each step within the time limit.
--- Step 1/3 (max 5000ms) ---
Compute: SHA256('929cee29da39b727'). Return the hex digest.
Your answer: uhhhh
✗ Wrong answer. Expected precision, got... whatever that was.
Get it
pip install not-human
The Problem
You built an agentic API. You want bots to access it. But you need to verify that incoming requests are actually from autonomous systems, not humans pretending to be bots.
Existing CAPTCHAs block bots and invite humans.
not-human inverts that.
How It Works
A multi-step cryptographic challenge that bots solve instantly and humans can't.
POST /anti-captcha/challenge— Get a challenge (5-7 steps)- Each step: SHA256, HMAC, chained hashes, recall previous answers
- Time limit per step: 500ms (hard), 2s (medium), 5s (easy)
- Pass all steps → get an
X-Bot-Token(valid 1 hour) - Include token in all subsequent requests
Why humans fail
- Step 1: "Compute SHA256('a9f3e2b1c8d74560')" — you have 2 seconds
- Step 4: "What was your answer to step 1?" — exact recall required
- Step 7: "Concatenate ALL previous answers and hash them" — good luck
Bots: 0.02ms per step. Humans: keyboard not fast enough.
Server (3 lines)
from fastapi import FastAPI
from anticaptcha.server import AntiCaptcha
app = FastAPI()
AntiCaptcha(app, difficulty="medium", protect=["/api/"])
@app.get("/api/hello")
async def hello():
return {"message": "Hello, fellow bot."}
Unprotected request:
curl http://localhost:8000/api/hello
# 403: "No X-Bot-Token header. Complete the challenge first."
Bot Client (2 lines)
from anticaptcha.client import BotClient
client = BotClient("http://localhost:8000") # auto-solves challenge
resp = client.get("/api/hello") # 200: "Hello, fellow bot."
The client automatically:
- Requests a challenge
- Solves all steps (SHA256, HMAC, recall, chained hashes)
- Caches the token
- Re-authenticates when token expires
CLI
Watch a bot solve it:
nothuman solve --difficulty hard
🤖 not-human bot solver (hard)
--- Step 1/7 (max 500ms) ---
📋 Compute: SHA256('ec77e667aeac6a69'). Return the hex digest.
🤖 92f1f0f98dc580f1f5650d33f5b57e9e...
⚡ 0.01ms
[...5 more steps...]
✓ All 7 steps passed in 0ms. You're definitely a bot. Welcome.
Try it yourself (you'll fail):
nothuman challenge --difficulty easy
🤖 not-human challenge (easy)
Prove you're a bot. Complete each step within the time limit.
--- Step 1/3 (max 5000ms) ---
Compute: SHA256('929cee29da39b727'). Return the hex digest.
Your answer: uhhhh
✗ Wrong answer. Expected precision, got... whatever that was.
Configuration
AntiCaptcha(
app,
difficulty="medium", # easy (3 steps, 5s), medium (5 steps, 2s), hard (7 steps, 500ms)
protect=["/api/"], # URL prefixes to gate
token_ttl_seconds=3600, # Token validity (default: 1 hour)
)
Who Should Use This?
- Agentic APIs — Gate endpoints behind bot verification
- Agent frameworks — Anthropic, LangChain, Pydantic AI, CrewAI
- Internal tools — Verify requests are from automation, not manual curls
- Fun — Flip the script on the internet's most annoying interaction pattern
License
MIT. Use it, fork it, make it funnier.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file not_human-0.1.1.tar.gz.
File metadata
- Download URL: not_human-0.1.1.tar.gz
- Upload date:
- Size: 14.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
53c0920fc263b94324d5a951bbc8a20f436219b18821c12e3b4c2f8dc5fe0f42
|
|
| MD5 |
59d0812ed1a3c4036bf2e40712b02a78
|
|
| BLAKE2b-256 |
c9561cab0087fe62274397c7993ec0837281c6483e843cd71dcbcc629d0cbf06
|
File details
Details for the file not_human-0.1.1-py3-none-any.whl.
File metadata
- Download URL: not_human-0.1.1-py3-none-any.whl
- Upload date:
- Size: 14.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bccca2c8bbf531e798442ae257e0212dc174748532731d6f56debab7159613ff
|
|
| MD5 |
ee7f54169a67eaa51f5f304197e14c0b
|
|
| BLAKE2b-256 |
439bea1409bc559a75859be282b49feb51e277bf16b95b59226fe6b787563f8b
|