Browserless
Audited from github.com/browserless/browserless
Browserless runs headless Chrome, Chromium, Firefox, Edge and WebKit as a managed Docker service, exposing them over WebSocket and REST to standard Playwright and Puppeteer client libraries so teams can run browser automation without managing browser infrastructure themselves.
- Language
- TypeScript
- Hosting
- Docker
- Running for
- 5 years
- Team
- 2-5 People
Why this architecture
A base Node.js/TypeScript image is specialized into per-browser Docker builds (and one combined multi-browser build) so deployments only ship the browser binaries and system libraries they actually need, while a single TypeScript server handles session pooling, queueing and protocol translation for all of them.
Tech stack by layer
5 technologies · audited Sep 17, 2026- Node.jsRuntime for the service; a custom HTTP/WebSocket server (src/server.ts, http.ts, router.ts) pools browser connections without a web framework.
- TypeScriptThe entire src/ tree is TypeScript, compiled with tsc and published with declaration files (build/exports.d.ts).
- PlaywrightPrimary automation protocol; playwright-core plus five version-pinned aliases let clients on older Playwright versions connect to matching routes.
- PuppeteerAlternate automation protocol via puppeteer-core, extended with @zorilla/puppeteer-extra and a stealth plugin for anti-detection.(inferred)
- Dockerdocker/ has eight image variants (base, chrome, chromium, edge, firefox, webkit, multi, sdk), each a multi-stage build FROM ghcr.io/browserless/base.
- GitHub ActionsPer-browser Docker build/publish workflows, CodeQL scanning, dependabot auto-merge, and release-please for automated versioning.
Browserless architecture diagram
Open SVGDiagram as text
- Playwright clients (playwright-core) → Browserless server (Node http + ws): WebSocket
- Puppeteer clients (puppeteer-core) → Browserless server (Node http + ws): WebSocket
- REST callers (/pdf · /screenshot) → Browserless server (Node http + ws): HTTP
- Browserless server (Node http + ws) → Limiter & queue (src/limiter.ts): admit / queue
- Browserless server (Node http + ws) → WebSocket proxy (http-proxy): upgrade
- WebSocket proxy (http-proxy) → Browser processes (Chromium · Firefox · WebKit): CDP / Playwright
- Limiter & queue (src/limiter.ts) → Browser processes (Chromium · Firefox · WebKit): launch
Key architectural decisions
5 decisions- 01
One base image, five browser-specific runtime images, built in two stages
docker/base/Dockerfile installs Node 24 and the full npm tree (including devDependencies) via nvm on Ubuntu 24.04. Each of docker/chrome, docker/chromium, docker/edge, docker/firefox and docker/webkit then runs a builder stage (tsc, function bundle, debugger install) FROM that base, followed by a runtime stage that runs npm prune --omit=dev and installs only that one browser via the Playwright CLI.
- 02
A single multi-browser image exists for platforms that need all engines
docker/multi/Dockerfile installs Chromium, Firefox and WebKit (and Chrome/Edge on linux/amd64 only, gated on the TARGETPLATFORM build arg) into one image, at the cost of a larger runtime image than the per-browser variants.
- 03
Playwright and Puppeteer are first-class, with several Playwright protocol versions pinned
package.json's playwrightVersions map ties named dependency aliases (playwright-1.59 .. playwright-1.63) to specific playwright-core releases so that /playwright/<version> routes stay compatible with older client libraries, alongside puppeteer-core for the Puppeteer-compatible /webdriver and default routes.
- 04
An SDK image lets extension authors build on top of the multi image
docker/sdk/Dockerfile is FROM ghcr.io/browserless/multi:latest, reinstalls with --include=dev so the extension toolchain (typescript, marked, typescript-json-schema) is present, and strips route folders that do not match the base image (e.g. Firefox-only builds drop the chrome/chromium/edge/webkit route directories).
- 05
API schemas and OpenAPI docs are generated from the TypeScript routes, not hand-written
scripts/build-schemas.js (typescript-json-schema) and scripts/build-open-api.js generate the request/response schemas and OpenAPI document served at /docs directly from the route definitions under src/routes, keeping documentation in sync with the implementation.
How Browserless is built
How Browserless is structured
The service itself is a single TypeScript package (@browserless.io/browserless) rooted at src/, with src/browserless.ts as the composition point and src/router.ts/src/http.ts/src/server.ts implementing routing and the HTTP/WebSocket server. Supporting modules cover concerns like src/limiter.ts (concurrency/queueing), src/monitoring.ts and src/metrics.ts (health and Prometheus-style metrics), src/network-security.ts and src/token.ts (auth), and src/webhooks.ts/src/hooks.ts (lifecycle events for extensions). The docker/ directory is where deployment topology is decided: docker/base is the shared builder image, and docker/chrome, docker/chromium, docker/edge, docker/firefox, docker/webkit and docker/multi each produce a runtime image for a specific browser (or all of them). docker/sdk is a separate image for building custom extensions, and bin/scaffold is a template package.json for a new extension project that depends on @browserless.io/browserless.
Backend & APIs
There is no HTTP framework dependency (no Express/Fastify/Koa in package.json); the server is built directly on Node's http and ws modules, with http-proxy used to tunnel WebSocket connections through to the underlying browser processes. Requests are validated with ajv against schemas that scripts/build-schemas.js generates from the TypeScript route definitions via typescript-json-schema; the same routes feed scripts/build-open-api.js, which produces the OpenAPI document served at /docs. src/config.ts centralizes environment-driven configuration, and src/network-security.ts plus src/token.ts implement token-based access control and network allow/deny rules.
Build, test & deploy
Compilation is plain tsc (build:ts), followed by steps that install ad-block filter lists (install:adblock), the Chrome DevTools frontend (install:devtools) and a debugger UI (install:debugger) as build artifacts (build:devtools, build:function). Tests run on Mocha with Chai assertions and c8 for coverage; mocha's config in package.json points at build/**/*.spec.js, so tests run against compiled output rather than source. Linting is ESLint via cross-env eslint . --fix, gated by Husky and lint-staged pre-commit hooks and a dedicated pr-prettier-check.yml workflow. Releases are automated with release-please (release-please-config.json, .release-please-manifest.json), which drives CHANGELOG.md and npm publishing (npm-publish.yml) in addition to the Docker image workflows.
Self-hosting notes
Each browser has its own two-stage Dockerfile: a builder stage FROM ghcr.io/browserless/base:$VERSION that compiles TypeScript and builds the function/debugger assets (inheriting base's full devDependencies install), and a runtime stage that runs npm prune --omit=dev, installs exactly one browser via playwright-core's CLI (--with-deps), and copies over the compiled build, static and extensions directories. docker/multi/Dockerfile follows the same pattern but installs Chromium and Firefox unconditionally, adds Chrome/Edge only on linux/amd64, and can install multiple WebKit versions side by side via scripts/install-versioned-browsers.sh when INSTALL_WEBKIT_VERSIONS=true. All runtime images run as a non-root blessuser account created in the base image. docker/sdk/Dockerfile builds FROM any of the above images (ARG FROM=ghcr.io/browserless/multi:latest) and reinstalls with --include=dev so an extension author's own browserless build/browserless docker commands (from bin/browserless.js) have the full toolchain available.
What to copy (and what not to)
The base-image-plus-per-variant-runtime-image pattern is a solid template for any service that needs to ship several large, mostly-shared native dependencies (here, browser binaries) without bloating every deployment with all of them. Generating both request-validation schemas and OpenAPI docs from the same TypeScript route definitions (build-schemas.js / build-open-api.js) is worth copying to avoid documentation drift. Be more careful before copying the licensing structure: this is a dual-licensed SSPL/commercial product, not a permissively licensed library, so forks intended for commercial or closed-source use need their own legal review rather than assuming standard open-source terms apply.
Sources & repo audit
- Audited
- Sep 17, 2026
- Commit
- 016ffa7
- License
- NOASSERTION
- Root package.json (playwright-core, puppeteer-core, playwrightVersions map, ws)
- docker/base/Dockerfile (Ubuntu 24.04, Node 24 via nvm, full npm install)
- docker/chrome/Dockerfile (two-stage builder/runtime pattern)
- docker/multi/Dockerfile (TARGETPLATFORM-gated multi-browser image)
- docker/sdk/Dockerfile (extension SDK image built on top of multi)
Independent analysis of repository at github.com/browserless/browserless. Spotted an inaccuracy? Use the claim form to request a correction.
Show this stack on your README or website
[](https://stackitfast.com/project/browserless)Paste it into your README. It shows your current stack and links to this page.
Scaffold it with your agent
Paste this prompt into Claude Code, Cursor, Windsurf or AGY to start a project with Browserless's architecture.
- 1Copy the promptThe full markdown spec, with every layer and decision.
- 2Open your AI toolClaude Code, Cursor, Windsurf or Copilot, in a new repo.
- 3Paste and scaffoldUse it as the first instruction; review before you ship.
# MISSION: Scaffold "Browserless" Production Architecture
You are an expert Senior Staff Software Architect and Full-Stack Engineer. Your mission is to scaffold and implement a production-grade, highly reliable, and modular codebase following the proven architecture of **Browserless**.
---
## 1. PROJECT SPECIFICATIONS & BENCHMARK
- **Reference Architecture**: Browserless
- **What It Does**: Browserless runs headless Chrome, Chromium, Firefox, Edge and WebKit as a managed Docker service, exposing them over WebSocket and REST to standard Playwright and Puppeteer client libraries so teams can run browser automation without managing browser infrastructure themselves.
- **Domain & Category**: Headless Browser Automation Infrastructure
- **Production Scale**: 2-5 People
- **Development Mode**: CLASSIC
- **Architectural Rationale**: A base Node.js/TypeScript image is specialized into per-browser Docker builds (and one combined multi-browser build) so deployments only ship the browser binaries and system libraries they actually need, while a single TypeScript server handles session pooling, queueing and protocol translation for all of them.
- **Live Website Reference**: https://browserless.io
- **Source Repository**: https://github.com/browserless/browserless
---
## 2. PRODUCTION TECH STACK
- **Full Stack Array**: TypeScript, Node.js, Docker, Playwright, Puppeteer
- **Primary Language(s)**: TypeScript, JavaScript, Dockerfile, Shell
- **License of the reference repo**: NOASSERTION
- **Backend & APIs**: Node.js — Runtime for the service; a custom HTTP/WebSocket server (src/server.ts, http.ts, router.ts) pools browser connections without a web framework.; TypeScript — The entire src/ tree is TypeScript, compiled with tsc and published with declaration files (build/exports.d.ts).; Playwright — Primary automation protocol; playwright-core plus five version-pinned aliases let clients on older Playwright versions connect to matching routes.; Puppeteer — Alternate automation protocol via puppeteer-core, extended with @zorilla/puppeteer-extra and a stealth plugin for anti-detection.
- **Infrastructure & deploy**: Docker — docker/ has eight image variants (base, chrome, chromium, edge, firefox, webkit, multi, sdk), each a multi-stage build FROM ghcr.io/browserless/base.; GitHub Actions — Per-browser Docker build/publish workflows, CodeQL scanning, dependabot auto-merge, and release-please for automated versioning.
---
## 3. KEY ARCHITECTURAL DECISIONS (audited from https://github.com/browserless/browserless @ 016ffa7)
1. **One base image, five browser-specific runtime images, built in two stages**: docker/base/Dockerfile installs Node 24 and the full npm tree (including devDependencies) via nvm on Ubuntu 24.04. Each of docker/chrome, docker/chromium, docker/edge, docker/firefox and docker/webkit then runs a builder stage (tsc, function bundle, debugger install) FROM that base, followed by a runtime stage that runs npm prune --omit=dev and installs only that one browser via the Playwright CLI.
2. **A single multi-browser image exists for platforms that need all engines**: docker/multi/Dockerfile installs Chromium, Firefox and WebKit (and Chrome/Edge on linux/amd64 only, gated on the TARGETPLATFORM build arg) into one image, at the cost of a larger runtime image than the per-browser variants.
3. **Playwright and Puppeteer are first-class, with several Playwright protocol versions pinned**: package.json's playwrightVersions map ties named dependency aliases (playwright-1.59 .. playwright-1.63) to specific playwright-core releases so that /playwright/<version> routes stay compatible with older client libraries, alongside puppeteer-core for the Puppeteer-compatible /webdriver and default routes.
4. **An SDK image lets extension authors build on top of the multi image**: docker/sdk/Dockerfile is FROM ghcr.io/browserless/multi:latest, reinstalls with --include=dev so the extension toolchain (typescript, marked, typescript-json-schema) is present, and strips route folders that do not match the base image (e.g. Firefox-only builds drop the chrome/chromium/edge/webkit route directories).
5. **API schemas and OpenAPI docs are generated from the TypeScript routes, not hand-written**: scripts/build-schemas.js (typescript-json-schema) and scripts/build-open-api.js generate the request/response schemas and OpenAPI document served at /docs directly from the route definitions under src/routes, keeping documentation in sync with the implementation.
---
## 4. NON-NEGOTIABLE ARCHITECTURAL GUARDRAILS
1. **Monorepo & Modular Separation**:
- Structure as a Turborepo monorepo with strict package boundaries:
- `apps/web`: Application UI, routing, layouts, and server endpoints.
- `packages/ui`: Shared design tokens, CSS variables, and Radix UI primitive components.
- `packages/db`: Database schemas, client singleton, declarative migrations, and seed scripts.
- `packages/config`: Shared TypeScript, ESLint, and build configurations.
2. **Strict Type Safety & Zero `any` Policy**:
- Enable `strict: true`, `noImplicitAny: true`, and `strictNullChecks: true`.
- Validate ALL external inputs, API request bodies, and query parameters with **Zod** schemas before execution.
3. **Frontend & Rendering Guidelines**:
- Isolate interactive UI state to leaf components. Keep core pages lightweight and performant.
4. **Design System & Aesthetics**:
- Keep every color, radius, shadow and font in a single token file (CSS variables) and consume tokens everywhere; never hardcode hex values in components.
- Prefer crisp 1px borders and one subtle shadow scale over blurry default shadows. Pair one sans-serif for body/headings with one monospace for tags, badges, metrics, and code.
5. **Data Layer & Reliability**:
- Write declarative schema definitions with foreign keys, composite indexes on queried filters, and automated timestamp triggers.
- Use connection pooling and prepared statements for serverless database execution.
---
## 5. STEP-BY-STEP SCAFFOLDING ROADMAP
- **Phase 1: Workspace & Root Config**: Initialize package manager, monorepo configuration (`turbo.json`, `tsconfig.base.json`, `package.json`).
- **Phase 2: Database Schema & Client**: Set up the data layer: client, connection pool, models, and migration scripts.
- **Phase 3: Design Tokens & UI Primitives**: Build accessible `Button`, `Input`, `Card`, `Badge`, and layout wrappers inside `packages/ui`.
- **Phase 4: Core Application Routes & Handlers**: Implement primary authentication, user session handling, and application routes.
- **Phase 5: Quality Assurance & Build Verification**: Run `tsc --noEmit`, ESLint, Prettier, and smoke test suites to ensure zero compilation or runtime errors.
---
## 6. EXECUTION INSTRUCTIONS
1. Review all specifications, architectural guardrails, and stack choices above.
2. Present the full monorepo directory tree structure.
3. Systematically generate the complete, production-ready codebase according to the 5-phase roadmap above — starting with the root workspace setup, followed by the database schema, UI design system package, and full-stack application routes until the repository is fully scaffolded and ready to run.Frequently asked about Browserless
What is Browserless built with?
Browserless is a TypeScript Node.js service with no web framework: a custom HTTP and WebSocket server (src/server.ts, src/router.ts) proxies connections from Playwright and Puppeteer clients to real browser processes running inside Docker containers.
Does Browserless need a backend database?
No. The repository has no database dependency in package.json; state is limited to in-process session/queue tracking (src/limiter.ts, src/metrics.ts) for the browsers it manages.
Can I self-host Browserless?
Yes — that is the primary distribution model. docker run -p 3000:3000 ghcr.io/browserless/chromium (per the README) runs a single-browser image; docker/multi provides an image with Chromium, Firefox and WebKit together, and docker/sdk supports building custom extensions on top of it.
How does Browserless support both Playwright and Puppeteer?
Both client libraries are dependencies (playwright-core and puppeteer-core), and package.json's playwrightVersions map pins several additional playwright-core releases under aliases like playwright-1.60, so the server can expose version-specific WebSocket routes for older Playwright clients alongside the default Puppeteer-compatible routes.
Is Browserless open source or commercial?
GitHub reports the repository's license as unrecognized (NOASSERTION), while package.json declares it SSPL; the README states it is dual-licensed under SPDX SSPL-1.0 or a Browserless commercial license, with the commercial license required for closed-source commercial or CI use.
Does Browserless use Chromium?
Yes, among others. docker/ builds separate images for Chromium, Chrome, Edge, Firefox and WebKit on a shared base image, plus a multi image that installs Chromium, Firefox and WebKit together.
One email a month: new deep dives and stack trends
New source-audited architectures, head-to-head comparisons and the monthly stack report. No spam, unsubscribe anytime.
Similar architectures
- Fast Jev CompactionClassicClaude Code Plugin · SoloShares TypeScript · Node.js
- Tailwind CSSClassicUtility-First CSS Engine & Framework · 1M+ MAUShares TypeScript · Node.js
- AstroHybridIsland Architecture Web Framework · 1M+ MAUShares TypeScript · Node.js
- tRPCHybridEnd-to-End Typesafe API Framework · 1M+ MAUShares TypeScript · Node.js
- Next.jsHybridFullstack React Framework · 1M+ MAUShares TypeScript · Node.js
- Supabase StudioClassicDeveloper Tool · 20+ peopleShares TypeScript · Docker