LLM Telepresence Browser Lab is a public remote browser environment for testing, demos, accessibility experiments, and user-owned video-chat labs. It gives LLM agents and browser tools a simple web UI plus HTTP/JSON API for creating isolated Chromium sessions, navigating pages, inspecting state, taking screenshots, and attaching synthetic camera or microphone sources.
- A Node.js, TypeScript, Fastify, Playwright, Vite, and React app.
- A browser-session controller designed for LLM-friendly operation.
- A fake camera lab using Chromium fake media devices and ffmpeg-generated Y4M files.
- A best-effort fake microphone lab using Chromium fake audio files, generated WAV assets, TTS, and documented host-level alternatives.
- A consent-first tool with visible generated-media disclosure support.
- Not a stealth, anti-detection, CAPTCHA bypass, credential theft, or platform-abuse tool.
- Not a way to impersonate people or enter conversations without permission.
- Not a guarantee that every WebRTC site will accept synthetic mic/camera sources.
- Not a replacement for OS-level virtual devices when live production audio/video routing is required.
Use it only on sites, accounts, rooms, meetings, and conversations where you have explicit permission to participate.
- Web UI at
/ - Session UI at
/session/:id - Text-only agent page at
/lite - Human-readable API docs at
/api-docs - LLM-native JSON API under
/api - Asset upload for images, videos, and audio
- Image/video conversion to Chromium-compatible fake webcam Y4M
- Optional generated-video disclosure watermark
- TTS WAV generation through
espeak-ngorespeakwhen installed - Screenshot, page-state, console-log, and recent-error diagnostics
- URL allow/block patterns, private-network blocking, upload limits, session TTL, and max-session controls
- Docker and Docker Compose support
Required:
- Node.js 22 or newer
- npm
- ffmpeg
- Playwright Chromium dependencies
Optional:
espeak-ngorespeakfor TTSsoxfor your own audio experiments- PulseAudio/PipeWire or
v4l2loopbackfor advanced host-level virtual devices
Install and build:
npm install
npm run build
npx playwright install chromium
cp .env.example .env
npm startOpen http://localhost:3000.
For development:
npm run devThe API runs on port 3000; Vite runs on port 5173 and proxies /api and /lite.
docker compose up --buildOpen http://localhost:3000. (Authentication has been removed; the API is public. Previous ADMIN_TOKEN / ALLOW_UNAUTHENTICATED_LOCAL env vars are ignored.)
This app includes complete, production-oriented scaffolding to deploy as a GCP Cloud Run web service (single container serving the React UI + Fastify API on one port).
The fully-working deploy script handles:
- API enablement, Artifact Registry repo creation
- Building the image (Cloud Build or local Docker)
- Creating/updating the Cloud Run service with browser-friendly resources (2 GiB memory, 2 CPU, low concurrency)
- Automatic
PUBLIC_BASE_URLconfiguration after deploy (so session links are correct) - Health verification + ready-to-run curl examples
(Note: the API is now public; previous secret/ADMIN_TOKEN handling for auth has been removed from the app.)
# Interactive (will prompt for project / generate token if needed)
./scripts/deploy-gcp.sh
# Or fully non-interactive (CI / automation friendly)
PROJECT_ID=my-gcp-project \
REGION=us-central1 \
SERVICE=telepresence-lab \
./scripts/deploy-gcp.sh --non-interactiveThe script is self-documenting and prints the live URL and post-deploy notes. (API auth tokens are no longer used.)
# One-time repo setup (or let the deploy script create it)
gcloud artifacts repositories create telepresence-images --repository-format=docker --location=us-central1
gcloud builds submit \
--config=cloudbuild.yaml \
--substitutions="_REGION=us-central1,_SERVICE=telepresence-lab,_REPO=telepresence-images"See cloudbuild.yaml (auth-related secret wiring has been removed since the API is now public).
Edit gcp/service.yaml (update the image reference), then:
gcloud run services replace gcp/service.yaml --region=us-central1
# Follow up to set the real URL:
URL=$(gcloud run services describe telepresence-lab --format='value(status.url)' --region=us-central1)
gcloud run services update telepresence-lab --update-env-vars PUBLIC_BASE_URL=$URL --region=us-central1- Memory/CPU: 2Gi + 2 vCPU (minimum realistic for Chromium + concurrent sessions; 512Mi will OOM).
- Concurrency: 1 (each active browser session is heavyweight; increase only if you cap MAX_SESSIONS very low).
- Max instances: 5 (tune together with
MAX_SESSIONS). - Ephemeral storage:
/data(assets, Y4M/WAV files, derived media) is per-instance and lost on restarts/scale-to-zero. Fine for demos, testing, and short-lived labs. Persistent storage would require app-level Cloud Storage integration. - PUBLIC_BASE_URL: Automatically set by the deploy script to the canonical
https://...run.appsoPOST /api/sessionsreturns usable absoluteweb/lite/etc. links. - Health:
/api/healthis used implicitly; the server also responds to Cloud Run lifecycle signals.
(The API is public; no ADMIN_TOKEN or IAM lockdown for auth is required.)
- Visit the service URL.
- Create a session and test a navigation + screenshot.
- Optionally set
ALLOWED_URL_PATTERNSor other restrictions via env var updates. - Monitor logs:
gcloud run services logs read telepresence-lab --region=us-central1 --limit=100
The root Dockerfile already produces a Cloud Run compatible image (Playwright installed with system deps at build time, dumb-init for signals, listens on $PORT).
Cloud Build + Artifact Registry is used because the image is large (Chromium) and benefits from remote caching / high-CPU builders.
Important environment variables:
MAX_SESSIONS: concurrent session limitSESSION_TTL_MS: automatic session cleanup intervalUPLOAD_MAX_BYTES: upload size limitALLOW_PRIVATE_NETWORKS: allows localhost/private-network navigation whentrueALLOWED_URL_PATTERNS: comma-separated glob patternsBLOCKED_URL_PATTERNS: comma-separated glob patternsDISCLOSURE_WATERMARK_ENABLED: adds disclosure text to generated camera videoDISCLOSURE_WATERMARK_LABEL: default watermark label
(Note: API authentication via ADMIN_TOKEN / ALLOW_UNAUTHENTICATED_LOCAL has been removed; all API endpoints are public. The /lite UI is also unauthenticated.)
Private, loopback, link-local, and reserved IP targets are blocked by default to reduce SSRF risk.
Create a session:
curl -s -X POST http://localhost:3000/api/sessions \
-H "content-type: application/json" \
-d '{}'Upload an avatar image:
curl -s -X POST http://localhost:3000/api/assets \
-F "file=@avatar.png"Set that image as the fake webcam:
curl -s -X POST http://localhost:3000/api/sessions/$SESSION/media/camera \
-H "content-type: application/json" \
-d '{"mode":"image","assetId":"ASSET_ID","disclosure":{"enabled":true,"label":"AI-assisted"}}'Navigate to a target site:
curl -s -X POST http://localhost:3000/api/sessions/$SESSION/navigate \
-H "content-type: application/json" \
-d '{"url":"https://example.com"}'Generate TTS audio:
curl -s -X POST http://localhost:3000/api/tts \
-H "content-type: application/json" \
-d '{"text":"Hello, I am testing audio.","voice":"default"}'Inspect state:
curl -s http://localhost:3000/api/sessions/$SESSION/stateTake a screenshot:
curl -s http://localhost:3000/api/sessions/$SESSION/screenshotPOST /api/sessionsGET /api/sessionsGET /api/sessions/:idDELETE /api/sessions/:idPOST /api/sessions/:id/navigatePOST /api/sessions/:id/clickPOST /api/sessions/:id/typePOST /api/sessions/:id/keyPOST /api/sessions/:id/evaluatePOST /api/sessions/:id/reloadPOST /api/sessions/:id/backPOST /api/sessions/:id/forwardGET /api/sessions/:id/screenshotGET /api/sessions/:id/stateGET /api/sessions/:id/streamPOST /api/sessions/:id/media/cameraPOST /api/sessions/:id/media/micGET /api/assetsPOST /api/assetsGET /api/assets/:id/filePOST /api/tts
More examples are in docs/api-examples.md.
- Chromium fake camera is the reliable path; uploaded images/videos are converted to Y4M and passed with
--use-file-for-fake-video-capture. - Changing fake camera or fake audio files requires relaunching that session’s Chromium instance. The app preserves the current URL, but in-page transient state may reset.
- Chromium fake mic support via
--use-file-for-fake-audio-capturevaries by platform and browser build. - Cloud containers usually cannot expose kernel-level virtual camera or microphone devices.
- Cross-origin pages cannot be embedded as iframes, so this app uses screenshots and API actions instead of direct embedding.
- Some websites block automation or require real user verification/consent.
- Browser permissions and WebRTC behavior vary by site and Chromium version.
- Browserless/noVNC or WebRTC remote desktop streaming
- PipeWire/PulseAudio virtual microphone mode
v4l2loopbackhost virtual camera integration- More TTS adapters and voices
- Avatar animation and lip sync
- Stronger queueing/locking for concurrent agent actions