A FastAPI service that manages SeleniumBase browser instances in subprocesses and exposes Chrome DevTools Protocol (CDP) endpoints via HTTP API.
- Thread-safe: Since SeleniumBase is not thread-safe, browsers run in isolated subprocesses
- Per-user API key authentication: Issue and revoke keys in format
sbcdp_<uid>_<random> - Reference counting: Safely share instances with identical params across multiple clients
- Graceful shutdown: Safely terminate all browsers on SIGTERM
sb-service/
├── pyproject.toml
├── .env.example
├── examples/
│ ├── client_example.py
│ ├── fetch_title.py
└── src/
└── sb_service/
├── __init__.py
├── app.py # FastAPI application
├── auth.py # User / API key management
├── manager.py # SBCDPManager (subprocess management)
└── worker.py # SeleniumBase subprocess worker
pip install -e .
# or with dev dependencies
pip install -e ".[dev]"cp .env.example .env
# Edit .env to set SB_ADMIN_KEY# Via scripts (recommended)
sb-cdp-serve
# Direct uvicorn
uvicorn sb_service.app:app --host 0.0.0.0 --port 8000
# Swagger UI Documentation
open http://localhost:8000/docs# Create user
curl -X POST http://localhost:8000/admin/users \
-H "X-Admin-Key: your_admin_key" \
-H "Content-Type: application/json" \
-d '{"username": "alice"}'
# → {"user_id": "a1b2c3", ...}
# Issue API key (full key shown only once)
curl -X POST http://localhost:8000/admin/users/a1b2c3/keys \
-H "X-Admin-Key: your_admin_key" \
-H "Content-Type: application/json" \
-d '{"label": "alice-main"}'
# → {"key": "sbcdp_a1b2c3_4f9e2d...", "key_id": "...", ...}# Start instance (201=new, 200=reused)
curl -X POST http://localhost:8000/instances \
-H "X-API-Key: sbcdp_a1b2c3_4f9e2d..." \
-H "Content-Type: application/json" \
-d '{"headless": true}'
# → {"cdp_ws_url": "ws://localhost:PORT/devtools/browser/...", ...}
# List instances (?mine=true for owned only)
curl http://localhost:8000/instances \
-H "X-API-Key: sbcdp_a1b2c3_4f9e2d..."
# Release instance
curl -X DELETE "http://localhost:8000/instances/{key_b64}" \
-H "X-API-Key: sbcdp_a1b2c3_4f9e2d..."
# Release all instances (admin key required)
curl -X DELETE http://localhost:8000/instances \
-H "X-Admin-Key: your_admin_key"examples/fetch_title.py demonstrates an end-to-end Playwright flow via sb-service:
- Creates a temporary user and API key
- Starts one browser instance per site using
browser_args - Connects via Playwright
connect_over_cdp() - Applies Playwright iPhone 13 device emulation when
browser_args.mobile=true - Captures one screenshot per site into
examples/snapshots/{name}.png - Prints current managed instances before cleanup
- Releases all instances in bulk with
DELETE /instances - Deletes the temporary user
Site configuration format:
SITES = [
{
"name": "qoo10_mobile",
"url": "https://www.qoo10.jp",
"browser_args": {
"headless": True,
"mobile": True,
},
"wait": 2,
},
]| Header | Scope | Purpose |
|---|---|---|
X-Admin-Key |
Admin | /admin/*, DELETE /instances |
X-API-Key |
User | /instances, /health |
| Variable | Default | Description |
|---|---|---|
SB_ADMIN_KEY |
"" |
Admin key (required) |
SB_KEY_STORE_PATH |
api_keys.json |
User/key persistence file |
SB_STARTUP_TIMEOUT |
60 |
Browser startup timeout (seconds) |
SB_SHUTDOWN_TIMEOUT |
10 |
Browser shutdown timeout (seconds) |
SB_MAX_INSTANCES |
0 |
Max concurrent instances (0=unlimited) |
SB_HOST |
0.0.0.0 |
Startup host |
SB_PORT |
8000 |
Startup port |
SB_RELOAD |
false |
uvicorn --reload |
SB_LOG_LEVEL |
INFO |
Log level |