Catalog PyPI
PACKAGE EXPLORERView in registry

aiocaptcha

PyPI

Minimal emoji captcha middleware for aiogram v3

Versions collected1
Direct dependencies1From release 0.1.0
Last observed21 Oct, 11:42 UTC

README

Version 0.1.0 documentation

AioCaptcha (aiogram middleware)

Minimal captcha middleware for aiogram v3.

Behavior:

  • Any user interaction with the bot is blocked until the user passes the captcha.
  • Captcha is an inline keyboard with emojis. The bot asks the user to click the required emoji.
  • Successful users can be stored persistently (SQLite) so they never need to pass captcha again.

Requirements

  • Python 3.10+ (recommended)
  • aiogram>=3.0.0

Install

pip install aiocaptcha

Quick start

Create a bot file like Source/main.py and run it.

1) Set the token

export BOT_TOKEN="YOUR_TELEGRAM_BOT_TOKEN"

2) Run

python Source/main.py

Usage

Minimal (in-memory)

Users will be considered “verified” only until the bot restarts.

from aiogram import Bot, Dispatcher
from aiocaptcha import CaptchaManager

bot = Bot(token="...")
dp = Dispatcher()

captcha = CaptchaManager()
captcha.setup(dp)

# ... register your handlers
await dp.start_polling(bot)
Persistent (SQLite)

Users who passed captcha will be stored in captcha.sqlite3 and won’t be asked again after restarts.

from aiogram import Bot, Dispatcher
from aiocaptcha import CaptchaManager, SqliteCaptchaStorage

bot = Bot(token="...")
dp = Dispatcher()

storage = SqliteCaptchaStorage("captcha.sqlite3")
captcha = CaptchaManager(storage=storage)
captcha.setup(dp)

await dp.start_polling(bot)

Note: SqliteCaptchaStorage uses a single connection with a lock and is fine for typical small bots.

Custom storage (your own)

You can provide your own storage to persist “verified” users.

The required interface is:

from typing import Protocol


class CaptchaStorage(Protocol):
  def is_verified(self, user_id: int) -> bool: ...

  def mark_verified(self, user_id: int) -> None: ...

  def reset(self, user_id: int) -> None: ...

Example: a simple file-backed JSON storage (minimal example):

import json
from pathlib import Path
from typing import Set

from aiocaptcha import CaptchaManager, CaptchaOptions


class JsonCaptchaStorage:
  def __init__(self, path: str = "verified.json") -> None:
    self.path = Path(path)
    self._verified: Set[int] = set()
    self._load()

  def _load(self) -> None:
    if not self.path.exists():
      return
    data = json.loads(self.path.read_text("utf-8"))
    self._verified = set(int(x) for x in data.get("verified", []))

  def _save(self) -> None:
    self.path.write_text(
      json.dumps({"verified": sorted(self._verified)}, ensure_ascii=False),
      "utf-8",
    )

  def is_verified(self, user_id: int) -> bool:
    return user_id in self._verified

  def mark_verified(self, user_id: int) -> None:
    self._verified.add(user_id)
    self._save()

  def reset(self, user_id: int) -> None:
    self._verified.discard(user_id)
    self._save()


opts = CaptchaOptions()
storage = JsonCaptchaStorage("verified.json")
captcha = CaptchaManager(options=opts, storage=storage)

For production/multi-instance setups, a Redis-based storage is usually a better fit.

Configuration

CaptchaOptions

Use CaptchaOptions to customize messages and emoji pool:

from aiocaptcha import CaptchaManager, CaptchaOptions

opts = CaptchaOptions(
    prompt_text="Please verify you're human by clicking {target}",
    passed_text="Captcha passed successfully! ✅",
    wrong_alert="Incorrect choice. Please try again.",
    pool=("🐶", "🐱", "🐭", "🐹", "🐰", "🦊", "🐻", "🐼"),
    choices=4,
    ttl_seconds=120,
)

captcha = CaptchaManager(options=opts)

Available options

  • callback_prefix — prefix for callback data (default: aiocaptcha)
  • pool — tuple of emojis
  • choices — how many buttons are shown
  • ttl_seconds — challenge expiration time
  • prompt_text — message template. Use {target}
  • passed_text — message after passing
  • wrong_alert — alert text on wrong click

How it works

Implementation notes
  • The library attaches:
    • an update-level middleware (dp.update.middleware(...)) that blocks all updates from non-verified users;
    • a small router that handles captcha callback queries.
  • When a non-verified user sends any message/clicks any button, the bot sends (or edits) a captcha message.
  • On correct click the user becomes verified; on wrong click the captcha regenerates.

Logging

Events and setup

The library logs events using Python logging under the logger name aiocaptcha:

  • captcha_passed user_id=...
  • captcha_failed user_id=... answer=... expected=...
  • captcha_sent user_id=... chat_id=... message_id=...

Enable logging in your app:

import logging

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(name)s: %(message)s",
)

Notes / limitations

Notes
  • Captcha state and verification are keyed by user_id.
  • In groups, a captcha message is sent to the chat where the interaction happened.
  • If you run multiple bot instances, use a shared storage (SQLite on shared disk, or implement your own storage like Redis).

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
0.1.05 Jan 20261

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

PENDING
limerboy/aiocaptcha

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 21 Oct, 11:42 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:6e8b2d789d9287cb254ac41164f3c8d0cac7cca3c4d9cd94a3930314b1c94eee