Skip to main content

Async-first, fully type-hinted, minimal captcha library with adapters for aiogram, FastAPI and Discord.

Project description

captchakit

Async-first, fully type-hinted captcha library for Python 3.10+. Zero runtime deps beyond Pillow. Drop-in adapters for FastAPI, aiogram and discord.py.

PyPI Python CI mypy: strict Ruff License: MIT


Why another one?

Feature lepture/captcha claptcha multicolorcaptcha captchakit
Async API
py.typed + mypy strict ⚠️
TTL & attempt tracking ✅ built-in
Pluggable storage Protocol
Framework adapters ✅ FastAPI · aiogram · discord.py
Runtime deps (core) +Pillow +Pillow +Pillow +Pillow

Install

pip install captchakit                  # core
pip install "captchakit[fastapi]"       # + FastAPI adapter
pip install "captchakit[aiogram]"       # + aiogram adapter
pip install "captchakit[discord]"       # + discord.py adapter
pip install "captchakit[redis]"         # + Redis storage + rate limiter
pip install "captchakit[postgres]"      # + Postgres storage backend
pip install "captchakit[django]"        # + Django form field + view
pip install "captchakit[metrics]"       # + Prometheus metrics adapter

See ROADMAP.md for what's next.

30-second example

import asyncio
from captchakit import (
    CaptchaManager, ImageRenderer, MemoryStorage, TextChallengeFactory,
)

async def main() -> None:
    manager = CaptchaManager(
        factory=TextChallengeFactory(length=5),
        renderer=ImageRenderer(),
        storage=MemoryStorage(),
        ttl=120.0,
        max_attempts=3,
    )
    challenge_id, png_bytes = await manager.issue()
    # ... show png_bytes to the user, receive their answer ...
    ok = await manager.verify(challenge_id, user_input="ABCDE")
    print("verified" if ok else "wrong answer, more attempts remain")

asyncio.run(main())

FastAPI in 10 lines

from fastapi import Depends, FastAPI
from captchakit import CaptchaManager, ImageRenderer, MathChallengeFactory, MemoryStorage
from captchakit.adapters.fastapi import captcha_router, verify_captcha

manager = CaptchaManager(MathChallengeFactory(), ImageRenderer(), MemoryStorage())
app = FastAPI()
app.include_router(captcha_router(manager, prefix="/captcha"))

@app.post("/register")
async def register(_: None = Depends(verify_captcha(manager))) -> dict[str, bool]:
    return {"ok": True}

Run the bundled demo:

uv run python -m uvicorn examples.fastapi_login:app --reload
# open http://127.0.0.1:8000

Design

┌─────────────────────────────────────────────────┐
│  Adapters (fastapi / aiogram / discord)         │
├─────────────────────────────────────────────────┤
│  CaptchaManager  (public facade)                │
├──────────────┬──────────────┬───────────────────┤
│  Challenge   │  Renderer    │  Storage          │
│  Text / Math │  Image (PIL) │  Memory / Redis   │
└──────────────┴──────────────┴───────────────────┘
  • Protocol-based, so you can drop in your own storage (Redis, Postgres, Memcached), your own renderer (SVG, WebP, audio), or your own challenge factory (wordlists, emoji grids, …).
  • Constant-time comparison via hmac.compare_digest.
  • Crypto-safe randomness via secrets for solution generation.
  • CPU-bound Pillow drawing offloaded to a worker thread via asyncio.to_thread, so the event loop never blocks.

Security scope

captchakit is a lightweight human-check, not a bot-farm-grade security layer. It is aimed at Telegram/Discord verification, simple FastAPI registration flows and similar use cases where you just want to raise the cost for casual spam.

For high-value forms (login, payment) use hCaptcha, Cloudflare Turnstile or reCAPTCHA Enterprise in addition. Combine captchakit with proper rate limiting at the edge of your application.

Roadmap

See ROADMAP.md for the full development plan.

Version Highlights
0.1 ✅ Core + Text/Math challenges + Image renderer + Memory storage + FastAPI
0.2 ✅ aiogram adapter + RedisStorage + EmojiGridChallenge
0.3 ✅ discord.py adapter + WordChallenge + docs site
0.4 ✅ AudioRenderer + Theme presets + i18n + Prometheus metrics
0.5 ✅ PostgresStorage + SVGRenderer + RateLimiter + Django adapter
1.0 Stable API, semver commitment

Contributing

Contributions welcome. Local development:

git clone https://github.com/akerem16/captchakit
cd captchakit
uv sync --all-extras
uv run ruff check .
uv run mypy
uv run pytest

License

MIT — see LICENSE.

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

captchakit-0.5.0.tar.gz (29.8 kB view details)

Uploaded Source

Built Distribution

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

captchakit-0.5.0-py3-none-any.whl (38.9 kB view details)

Uploaded Python 3

File details

Details for the file captchakit-0.5.0.tar.gz.

File metadata

  • Download URL: captchakit-0.5.0.tar.gz
  • Upload date:
  • Size: 29.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for captchakit-0.5.0.tar.gz
Algorithm Hash digest
SHA256 519c038452a86ff7db580a115d5acd16d73a3db0f97bc77e017d0a2dee035332
MD5 0c430fd89cebc79bfac5d6ff0d0c5377
BLAKE2b-256 961eef80786544b39d3290c5a69954736d2f79e5a4ba3775aa4c021348c4076b

See more details on using hashes here.

Provenance

The following attestation bundles were made for captchakit-0.5.0.tar.gz:

Publisher: release.yml on akerem16/captchakit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file captchakit-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: captchakit-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 38.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for captchakit-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5a568d77c064526325e52f930c10ae7b41e5867f5e31f9e09b44116af79295bb
MD5 5f690990d335dfe5a0f9070f3317569e
BLAKE2b-256 2cf4dcc8681b298b9554c9a3418355166df6e2df9ad45bc2bd8a165bff201807

See more details on using hashes here.

Provenance

The following attestation bundles were made for captchakit-0.5.0-py3-none-any.whl:

Publisher: release.yml on akerem16/captchakit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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