Skip to main content

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.

  1. POST /anti-captcha/challenge — Get a challenge (5-7 steps)
  2. Each step: SHA256, HMAC, chained hashes, recall previous answers
  3. Time limit per step: 500ms (hard), 2s (medium), 5s (easy)
  4. Pass all steps → get an X-Bot-Token (valid 1 hour)
  5. 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:

  1. Requests a challenge
  2. Solves all steps (SHA256, HMAC, recall, chained hashes)
  3. Caches the token
  4. 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

not_human-0.1.1.tar.gz (14.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

not_human-0.1.1-py3-none-any.whl (14.7 kB view details)

Uploaded Python 3

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

Hashes for not_human-0.1.1.tar.gz
Algorithm Hash digest
SHA256 53c0920fc263b94324d5a951bbc8a20f436219b18821c12e3b4c2f8dc5fe0f42
MD5 59d0812ed1a3c4036bf2e40712b02a78
BLAKE2b-256 c9561cab0087fe62274397c7993ec0837281c6483e843cd71dcbcc629d0cbf06

See more details on using hashes here.

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

Hashes for not_human-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 bccca2c8bbf531e798442ae257e0212dc174748532731d6f56debab7159613ff
MD5 ee7f54169a67eaa51f5f304197e14c0b
BLAKE2b-256 439bea1409bc559a75859be282b49feb51e277bf16b95b59226fe6b787563f8b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page