File size: 2,981 Bytes
2e38705
 
 
 
 
 
69f12cd
2e38705
 
 
69f12cd
 
 
 
 
 
 
 
 
 
579a226
 
 
 
 
 
 
 
 
f26e640
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
579a226
 
 
 
f26e640
 
 
 
579a226
 
 
 
 
 
 
 
 
 
f26e640
 
 
579a226
f26e640
 
579a226
f26e640
579a226
69f12cd
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
---
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.