Spaces:
Paused
Paused
| title: Playwright | |
| emoji: π₯ | |
| colorFrom: green | |
| colorTo: yellow | |
| sdk: docker | |
| app_port: 7860 | |
| pinned: false | |
| # Playwright API | |
| Public Playwright execution API. POST `/run` with JSON body: | |
| ```json | |
| { "code": "const { chromium } = require('playwright'); ..." } | |
| ``` | |
| Code may use either CommonJS (`require`) or ESM (`import`). | |
| ## Endpoints | |
| | Method | Path | Description | | |
| |--------|-------------|--------------------------------------| | |
| | GET | `/` | HTML landing page | | |
| | GET | `/api/info` | service info as JSON | | |
| | GET | `/health` | liveness probe | | |
| | POST | `/run` | execute Playwright code | | |
| ## Helpers in user code | |
| ```js | |
| const playwright = require('playwright'); | |
| const stealth = require('stealth'); // anti-bot launch wrapper | |
| const captcha = require('captcha'); // local CAPTCHA solvers + solver client | |
| ``` | |
| The bundled CAPTCHA suite β no third-party APIs, no per-solve fees: | |
| - **Turnstile / "Just a moment"** β `captcha.solveTurnstile(page)` and | |
| `captcha.clearChallenge(siteurl)` use the bundled solver service | |
| (Camoufox, runs in the same container). | |
| - **reCAPTCHA v2** β `captcha.solveRecaptchaV2(page)` does the audio | |
| fallback flow with local Whisper. | |
| - **Text/image CAPTCHA** β `captcha.ocrBuffer(buf)` via local Tesseract. | |
| - **Math CAPTCHA** β `captcha.solveMath('2 + 3 * 4')`. | |
| - **Cookie jar** β `captcha.saveCookies / loadCookies` to skip re-solving | |
| challenges on subsequent requests. | |
| ## Deploy | |
| ### Hugging Face Space | |
| Push to `git@hf.co:spaces/<user>/<name>`. The Dockerfile bundles both the | |
| Playwright API and the Turnstile solver in a single image (HF only allocates | |
| one container per Space). A supervisor script starts the solver in the | |
| background and the API in the foreground. | |
| ### VPS / your own server | |
| ```sh | |
| git clone https://github.com/cv3inx/playwright.git | |
| cd playwright | |
| cp .env.example .env | |
| docker compose up -d --build | |
| ``` | |
| Compose runs two containers on an internal Docker network: | |
| - `playwright-api` (port 7860 β host) β the API | |
| - `turnstile-solver` (port 9988, internal only) β the solver | |
| Wired automatically β `playwright-api` calls `http://turnstile-solver:9988` | |
| inside the network. No external URLs, no API keys. | |
| For HTTPS, put nginx/caddy/traefik in front of port 7860. | |
| ## Hardening | |
| Each request runs in an isolated process tree under a per-request workspace | |
| (`/tmp/run-<id>`) with strict ulimits, stripped env, and `setpriv --no-new-privs`. | |
| On completion (success, error, or timeout), the entire process group is | |
| SIGKILL'd, the session is wiped (`pkill -s`), the workspace is `rm -rf`'d, and | |
| orphaned chromium SHM segments are cleaned up β preventing any binary the | |
| script wrote from persisting between requests. | |
| Concurrent requests are isolated from each other: each gets its own pgid, | |
| session, and workspace, so one request's burn cannot disrupt another in flight. | |