# Robotex Browser automation API with built-in anti-bot stealth. Send a URL and a sequence of declarative actions — fill a field, click, wait for an element — and get back the rendered page, including sites behind Cloudflare-style JS challenges. ## Status Early MVP (v0), under active development. Single browser engine, no queue, no billing yet — see [Roadmap](#roadmap). ## Architecture ``` Client → Caddy (TLS) → FastAPI → API-key auth → semaphore acquire │ ▼ Chrome (Patchright) context (run actions, collect result) │ ▼ release semaphore → response ``` - **Engine**: real Google Chrome (`channel="chrome"`) driven via [Patchright](https://github.com/Kaliiiiiiiiii-Vinyzu/patchright-python) (undetected Playwright fork), headful under Xvfb. Firefox is not supported yet. - **API**: FastAPI, single versioned endpoint (`POST /v1/solve`). - **Concurrency**: bounded by an `asyncio.Semaphore` over browser contexts — no external job queue in v1. Simpler to run, hard ceiling on throughput per instance (see Roadmap for scaling out). - **Auth**: per-client API key (`X-API-Key` header), checked against a SQLite table. (SQLAlchemy ORM) - **Logging**: every request's outcome (success/failure/duration) is persisted — this becomes the success-rate data used to evaluate the service and talk to clients about reliability. - **Proxies**: not managed by the service in v1 — the client supplies their own proxy per request if they need one. - **Deployment**: single Docker container behind a Caddy reverse proxy — see [Docker](#docker) and [docs/Deployment.md](docs/Deployment.md). - **Canvas fingerprint** по дизайну генерируется каждую сессию новый. ### Project layout ``` src/ main.py # FastAPI app, POST /v1/solve api/ actions.py # fill / click / wait_for execution schemas.py # SolveRequest / Action models geoip.py # proxy → locale / timezone engine/ stealthy.py # AsyncStealthySession (Patchright + Chrome) session.py # browser / context launch options page_pool.py # page pool antibot/ # anti-bot detection & bypass orchestrator (Cloudflare, reCAPTCHA) captcha/ # captcha solvers (Turnstile, reCAPTCHA, hCaptcha) tests/ wheels/ # whl библиотеки для оффлайн установки под Ubuntu Noble Dockerfile docker-compose.yml .dockerignore requirements.txt env.example ``` ## API (draft) ``` POST /v1/solve X-API-Key: { "captcha": "token", "url": "https://example.com/login", "actions": [ {"type": "fill", "selector": "#email", "value": "user@example.com"}, {"type": "fill", "selector": "#password", "value": "..."}, {"type": "mouse_move", "selector": "#submit"}, {"type": "click", "selector": "#submit"}, {"type": "wait_for", "selector": ".dashboard", "timeout": 30} ], "proxy": "socks5://user:pass@host:port", "screen": "1280x920", "user_agent": "Mozilla/5.0 (...) Chrome/...", "timeout": 120 } ``` Response: ```json { "ok": false, "context": "000000", "error": "action_error", "html": "...", "cookies": [ { "name": "session", "value": "..." } ], "actions_result": [ { "type": "fill", "ok": true }, { "type": "fill", "ok": true }, { "type": "click", "ok": true }, { "type": "wait_for", "ok": false, "error": "Element not located" } ] } ``` On failure, `status` is `"error"` and `error` carries a machine-readable reason (`selector_not_found`, `timeout`, `navigation_failed`, ...). Fill команда включает 3 действия 1. `{"type": "mouse_move", "selector": "#email"},` - навести мышку на элемент 2. `{"type": "click"},` - клик в текущие координаты 3. `{"type": "typing", "value": "user@example.com"},` - набор текста ## Roadmap Deliberately out of scope for v1: - Job queue (Redis/RabbitMQ) + multiple worker VPS for horizontal scaling - Real billing/usage plans beyond a flat API-key check - Broader action vocabulary beyond fill/click/wait_for - Second engine (Firefox, e.g. Camoufox) for targets where the Chrome fingerprint doesn't fit ## Local development ```bash python -m venv .venv source .venv/bin/activate make sync-offline cd src && uvicorn main:app --reload ``` ## Docker ```bash docker compose up -d --build ``` The API listens on `http://localhost:8000`. Browser profiles (`extra/user_data_dir`) and the GeoIP cache live in the `extra` named volume, so sessions survive container restarts. Details (Xvfb, tini, `/dev/shm`) — [docs/Deployment.md](docs/Deployment.md).