A distributed hCaptcha solving system consisting of a FastAPI backend and an Electron desktop worker app.
Client (HTTP)
│
▼
┌─────────────┐ WebSocket ┌──────────────────┐
│ Backend │◄──────────────►│ Desktop Worker │
│ (FastAPI) │ │ (Electron) │
└─────────────┘ └──────────────────┘
- Backend — receives solve requests via REST, queues them, and dispatches tasks to connected desktop workers.
- Desktop — Electron app that connects to the backend over WebSocket, receives tasks, solves captchas using an embedded browser view, and returns the token.
Business rules, contracts and the standard test target live in REGRAS_NEGOCIOS.md.
Both sides also write rotating log files (backend/logs/hcaptcha-backend.log,
desktop/logs/hcaptcha-desktop.log). Override the directory with
HCAPTCHA_LOG_DIR.
The desktop worker additionally dumps every challenge it sees to
desktop/logs/challenges/<task_id>/ (prompt, reference image, 3x3 grid, and a
DOM integrity audit). See RN-24/RN-25 in REGRAS_NEGOCIOS.md.
With HCAPTCHA_COLOR_TAGGING=1 the worker replaces the challenge image bytes
with solid colors at the network layer, so an external automation (PyAutoGUI) has
a stable visual target. The DOM is never touched: tiles still point at the
original imgs.hcaptcha.com URLs. Each stage gets a colors.json with the
color-to-position map plus absolute screen coordinates, and a dom-audit.json
proving the DOM is unchanged.
cd desktop && HCAPTCHA_COLOR_TAGGING=1 npm run devHCaptchaSolver/
├── backend/ # Python FastAPI server
│ ├── main.py
│ ├── requirements.txt
│ ├── core/
│ │ ├── models.py # Task and Worker dataclasses
│ │ └── worker_manager.py # Task queue and worker dispatch
│ ├── routers/
│ │ └── tasks.py # REST endpoints
│ └── ws/
│ └── worker.py # WebSocket handler for workers
├── desktop/ # Electron + React + TypeScript worker app
│ └── src/
│ ├── main/ # Electron main process
│ ├── renderer/ # React UI
│ └── preload/ # Preload scripts
└── automation/ # Solver local (fora do app): decisor por LLM + PyAutoGUI
├── pipeline.py # task -> checkbox -> captura -> LLM -> cliques -> botao
├── vision.py # decisor por visao (JSON Schema estrito)
├── solve.py # sheet / checkbox / click / press / verify
└── mouse_human.py # movimento humanizado (Fitts + Bezier + minimo jerk)
Pipeline de referência, do POST da task ao token:
cp .env.example .env # preencha HCAPTCHA_LLM_ENDPOINT/API_KEY
automation/.venv/bin/python -u automation/pipeline.py --max-stages 3- O decisor de quais tiles clicar é um LLM com visão: a folha de contato
(
sheet-*.png, exemplo + grid 3x3 numerado) é enviada e a resposta volta em JSON Schema estrito ({"tiles":[1,5,9],...}). Ver RN-27. - O clique é sempre input real (
PyAutoGUI) em coordenada absoluta, com o movimento humanizado demouse_human.py. Antes de cada clique o solver confirma que a janela do Electron está em foco e que a cor no alvo confere; se não estiver, aborta em vez de clicar na janela errada. - O hCaptcha roda um proof-of-work (
hsw.js) antes de mostrar o checkbox — em torno de 30 s neste ambiente. O desafio também se renova sozinho depois de ~90 s sem interação, então o ciclo tem que ser rápido. - Artefatos de cada execução:
automation/out/sheet-*.png,llm-*.json(resposta do modelo),plano-*.png(caminho previsto),depois-*.pngeclick-*.json(traço do mouse).
cd backend
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtpython main.pyServer starts on http://0.0.0.0:8000.
POST /api/task
Content-Type: application/json
{
"sitekey": "af4fc5a3-1ac5-4e6d-819d-324d412a5e9d",
"siteurl": "https://solucoes.receita.fazenda.gov.br",
"proxy": "http://user:pass@host:port"
}Supported proxy schemes: http, https, socks5, socks5h.
The values above are the standard test target — use them for every manual or smoke test.
Returns the solved token (blocks until a worker completes it, timeout 120 s):
{ "token": "<captcha-token>" }GET /api/workers{ "total": 2, "available": 1 }Workers connect to ws://<host>:8000/ws/worker and exchange JSON messages:
| Direction | Message |
|---|---|
| Worker → Server | { "type": "register" } |
| Server → Worker | { "type": "registered", "worker_id": "..." } |
| Server → Worker | { "type": "task", "task_id": "...", "sitekey": "...", "siteurl": "...", "proxy": "..." } |
| Worker → Server | { "type": "result", "task_id": "...", "token": "..." } |
| Worker → Server | { "type": "error", "task_id": "...", "message": "..." } |
cd desktop
npm installnpm run devnpm run build:linux # Linux
npm run build:win # Windows
npm run build:mac # macOS