Doramagic Project Pack ยท Human Manual
steel-browser
๐ฅ Open Source Browser API for AI Agents & Apps. Steel Browser is a batteries-included browser sandbox that lets you automate the web without worrying about infrastructure.
Overview & System Architecture
Related topics: Sessions, Quick Actions & Browser Integrations, Plugin System, Chrome Extensions & Anti-Detection, Deployment, Configuration & Troubleshooting
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: Sessions, Quick Actions & Browser Integrations, Plugin System, Chrome Extensions & Anti-Detection, Deployment, Configuration & Troubleshooting
Overview & System Architecture
Purpose & Scope
Steel is an open-source browser API designed to give AI agents and applications programmatic control over real Chrome instances without the need to build browser-automation infrastructure from scratch. The project exposes a REST surface for session lifecycle, scraping, screenshots, PDF generation, and search, while delegating browser control to Puppeteer/Chrome DevTools Protocol (CDP) under the hood Source: [README.md].
The system is delivered as a self-hostable bundle (one combined Docker image) and is also offered as a managed "Steel Cloud" service. The same API is consumed by official Node and Python SDKs (steel-sdk), and clients can attach to running sessions with Puppeteer, Playwright, or Selenium because the underlying transport is standard CDP Source: [README.md].
The repository scope deliberately covers: full browser control, persistent session state, proxy chain management, custom extension loading, request/debug logging, anti-detection (stealth plugins and fingerprint management), automatic resource cleanup, and conversion utilities for markdown/readability/screenshot/PDF output Source: [README.md]. Community issue #123 confirms that users expect deeper documentation on these feature areas, so this overview surfaces the architectural shape that underpins them.
System Components
The repository is organized as a monorepo with three independently versioned workspaces plus an extensions folder. Each package has its own package.json and runs as a distinct process in development, while the production Docker image bundles them.
| Component | Path | Runtime | Primary Responsibility |
|---|---|---|---|
| API server | api/ | Fastify 5 on Node โฅ22 | REST API, session orchestration, CDP proxy, scrape/screenshot/PDF actions |
| Web UI | ui/ | React 18 + Vite + Radix | Operator dashboard, session debugger, recording playback |
| REPL | repl/ | Node + tsx + puppeteer-core | Local scripting harness that connects to a live CDP endpoint |
| Recorder extension | api/extensions/recorder/ | Chromium extension (rrweb) | Captures DOM events inside the page for later replay |
The API package owns the long-lived browser processes; the UI is a stateless viewer and controller; the REPL is a developer convenience; and bundled extensions are loaded into the browser at launch. The recorder extension notably pulls rrweb and @rrweb/packer to serialise page activity, which the UI replays using rrweb-player Source: [api/extensions/recorder/package.json].
Architecture & Data Flow
Steel follows a layered design: external clients hit the Fastify API, the API owns session managers that wrap Puppeteer pages, and Puppeteer talks to Chrome over a local CDP WebSocket. The WebSocket is also exposed outward so that SDKs and end-user scripts can attach Puppeteer/Playwright/Selenium to the same browser that backs the REST actions Source: [README.md].
flowchart LR
Client[Client / SDK / REPL] -->|REST| API[Fastify API - api/]
Client -.->|CDP WebSocket| Browser[Chrome Instance]
API -->|Puppeteer-core 23.6.0| Browser
API --> Schema[Zod Schemas - utils/schema.ts]
API --> Scrape[Scrape utilities - scrape/pdfToHtml.ts, scrape/jsonToMarkdown.ts]
API --> Cast[Page Casting - utils/casting.ts]
API --> Filter[URL Pattern Filters - utils/requests.ts]
UI[React UI - ui/] -->|REST + WS| API
Browser --> Recorder[rrweb Recorder Extension]
Recorder --> UIKey cross-cutting concerns are implemented as shared utilities under api/src/utils/:
- Schema layer uses Zod with a custom
buildJsonSchemashelper to produce OpenAPI 3 documents that power both runtime validation and the bundled Swagger UI Source: [api/src/utils/schema.ts]. - Scrape layer converts responses into structured formats.
pdfToHtml.tswraps MuPDF to render PDFs back into HTML with title, sections, and link extraction Source: [api/src/utils/scrape/pdfToHtml.ts];jsonToMarkdown.tspretty-prints JSON bodies inside fenced code blocks Source: [api/src/utils/scrape/jsonToMarkdown.ts]. - Casting layer applies remote navigation events (back/forward/refresh/goto) to a target Puppeteer page and fetches title and favicon metadata for the UI Source: [api/src/utils/casting.ts].
- Request filter layer compiles user-supplied URL patterns into case-insensitive regular expressions and applies allow/deny host lists Source: [api/src/utils/requests.ts].
The REPL package is intentionally minimal โ it declares only puppeteer-core and tsx as runtime/dev dependencies and a single start script, confirming that it is meant to attach to an already-running API rather than spin up its own browser Source: [repl/package.json].
Technology Stack & Integration Patterns
The runtime stack is deliberately narrow. On the server side, Fastify 5 with plugins for CORS, multipart, sensible defaults, static, view, and Swagger powers the HTTP surface; [email protected] is the single browser-control dependency; and proxy-chain, http-proxy, https-proxy-agent, and socks-proxy-agent together implement the proxy-chain feature called out in the README Source: [api/package.json]. Anti-detection is delivered through [email protected] and [email protected], which are pinned to identical versions to keep the generator/injector pair in lockstep Source: [api/package.json].
The UI package is a Vite-bundled SPA that consumes a generated OpenAPI client via @hey-api/openapi-ts, renders with Radix primitives and Tailwind, and uses rrweb-player to replay recordings produced by the recorder extension Source: [ui/package.json]. This codegen-driven approach means the UI never drifts from the API surface as long as npm run generate-api is re-run after schema changes.
Configuration is environment-driven (dotenv), and the production image exposes port 3000 for the API and 9223 for the CDP endpoint. The README documents one-liner Docker, Railway, and Render deploys, plus a local docker run command that maps both ports Source: [README.md].
Known Limitations & Operational Considerations
Several architectural boundaries are visible directly from the source:
- Single-node session affinity. Each Chrome process is bound to the API node that launched it. Community issue #144 highlights the lack of built-in cluster support and session routing across nodes; the current architecture does not provide that out of the box.
- Fingerprint generator brittleness. Because the API pins
fingerprint-generatorandfingerprint-injectorto the same minor version, a Chrome upgrade can break fingerprint consistency. Issues #295 and #302 both report "Failed to generate a consistent fingerprint after 10 attempts" with Chrome 146 at 1920x1080, forcing operators to setSKIP_FINGERPRINT_INJECTIONas a workaround. Operators should treat the fingerprint versions as a coupled unit when planning Chrome upgrades Source: [api/package.json]. - Local-dev runtime requirements. Issue #230 shows a
ReferenceError: File is not definedwhen runningnpm run devon Node versions missing theFileglobal. Bothapiandreplworkspaces declare"node": ">=22.0.0"in their engines, which is the supported floor for local development Source: [repl/package.json]. - Security posture is operator-managed. The README describes Steel as a tool for building agents, and the project has an active coordinated vulnerability disclosure program (issue #311). Self-hosters are responsible for network exposure, proxy trust, and CSP for any custom extensions they bundle.
See Also
- Sessions & Browser Lifecycle โ how session managers launch, persist, and release Chrome instances
- Anti-Detection & Fingerprinting โ how
fingerprint-generatorandfingerprint-injectorare wired into launches - Action Endpoints (Scrape / Screenshot / PDF) โ the
/v1/scrape,/v1/screenshot, and/v1/pdfsurface documented in the README - Deploying Steel โ Docker, Railway, and Render deployment paths referenced in the README
Source: https://github.com/steel-dev/steel-browser / Human Manual
Sessions, Quick Actions & Browser Integrations
Related topics: Overview & System Architecture, Plugin System, Chrome Extensions & Anti-Detection
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: Overview & System Architecture, Plugin System, Chrome Extensions & Anti-Detection
Sessions, Quick Actions & Browser Integrations
Overview
Steel exposes three complementary ways to drive a Chromium instance: Sessions for stateful, long-lived browser workflows; Quick Actions (/scrape, /screenshot, /pdf) for one-shot read-only jobs; and Browser Integrations (Puppeteer, Playwright, Selenium, raw CDP) that let external automation frameworks attach to the same browser process. Together they cover the spectrum from low-level CDP control to high-level content extraction, all behind a Fastify HTTP API documented at http://localhost:3000/documentation Source: README.md:1-120.
The api package registers these capabilities as a Fastify plugin tree. The top-level routes.ts mounts the sessions and actions modules and the SDK exports in api/package.json expose the same building blocks as typed packages (./plugin, ./cdp-plugin, ./logger, ./storage, ./browser) Source: api/package.json:1-60. This layered design is what allows the official Node and Python SDKs and the bundled repl to all speak to a single browser instance.
flowchart LR
Client["SDK / curl / Puppeteer / Playwright"] -->|HTTP| API["Fastify API<br/>(api/src/routes.ts)"]
API --> Sessions["/v1/sessions<br/>sessions.controller.ts"]
API --> Actions["/v1/{scrape,screenshot,pdf}<br/>actions.controller.ts"]
API --> CDP["CDP endpoint (9223)"]
Sessions --> Browser["Puppeteer-core<br/>Chrome Process"]
Actions --> Browser
CDP --> Browser
Browser --> Repl["@steel-browser/repl<br/>(puppeteer-core)"]Sessions: Stateful Browser Lifecycle
Purpose and Shape
The Sessions module is the centerpiece for stateful automation. It creates, releases, resets, and releases browser contexts, and persists cookies, localStorage, sessionStorage, and IndexedDB so workflows can be paused and resumed. The schema is defined in sessions.schema.ts and exposed as REST endpoints in sessions.routes.ts Source: api/src/modules/sessions/sessions.routes.ts:1-80.
SessionData in the context utilities formalizes what is captured per origin:
| Storage Domain | CDP Domain Used | Notes |
|---|---|---|
localStorage | DOMStorage.getDOMStorageItems | Key/value per origin |
sessionStorage | DOMStorage.getDOMStorageItems | Tab-scoped key/value |
indexedDB | IndexedDB queries | Database + object store records |
| Cookies | Network.getCookies | Re-injected on relaunch |
Source: api/src/utils/context.ts:1-60.
Lifecycle Hooks
Steel ships a plugin lifecycle that includes the most recent additions from v0.5.3-beta: onSessionStart, onBeforeSessionEnd, and onAfterSessionEnd. These hooks let plugin authors react when a session is created, about to close, or has just released its resources, complementing the earlier onBrowserReady hook (which now also supports promises) Source: Release v0.5.3-beta, Release v0.5.0-beta.
A typical session flow is:
POST /v1/sessionswith options such asproxyUrl,userDataDir,extensionIds,isSelenium, orfullscreenSource: README.md:90-130.- The controller launches Puppeteer, applies the fingerprint and extension, and returns
{ id, wsUrl, debuggerUrl, viewerUrl }. - Downstream calls (e.g.
POST /v1/sessions/:id/contextorDELETE /v1/sessions/:id/release) round-trip through the controller and invoke the relevant plugin hooks. - Resource cleanup is consolidated; the v0.4.5-beta release explicitly fixed default download behavior and error flows for session teardown Source: Release v0.4.5-beta.
SDK Usage
The Node and Python SDKs are thin wrappers around these routes. They expose a typed client.sessions.create({ ... }) and client.sessions.release(id) API and allow swapping the cloud endpoint via the baseURL / base_url option for self-hosted deployments Source: README.md:140-180.
Quick Actions: One-Shot Extraction
Quick Actions are read-only HTTP endpoints that boot a transient session, perform a single action, and return the result. They are documented as ideal for "simple, read-only, on-demand jobs" and are mounted under /v1 Source: README.md:150-200.
The three actions currently supported:
| Endpoint | Body | Result |
|---|---|---|
POST /v1/scrape | { url, delay, ... } | Cleaned HTML/markdown via Defuddle |
POST /v1/screenshot | { url, fullPage, ... } | PNG image of the page |
POST /v1/pdf | { url, ... } | Rendered PDF (parses back to HTML on retrieval) |
Source: README.md:150-200, api/src/utils/scrape/readability.ts:1-30.
Content Extraction Internals
getDefuddleContent runs Defuddle once on the raw HTML and inspects the result. If the result is "thin" (no markdown or fewer than 50 words and no extractor type), a second pass runs with aggressive stripping (<script>, <style>, <noscript> removed) and a relaxed selector set. The richer of the two passes wins, and its content/contentMarkdown/wordCount fields replace the originals Source: api/src/utils/scrape/readability.ts:1-60.
PDFs follow a parallel path: the pdfToHtml.ts utility uses mupdf to walk sections, collect links, and wrap the result in an HTML envelope with metadata (title, info:ModDate). The scrape action can therefore return either HTML scraped from a live page or HTML reconstructed from a PDF Source: api/src/utils/scrape/pdfToHtml.ts:1-40, api/package.json:30-80.
Browser Integrations: CDP, Puppeteer, Playwright, Selenium
CDP and the bundled REPL
Steel exposes a WebSocket CDP endpoint (default port 9223) that is compatible with any CDP client. The bundled repl package wires this endpoint to puppeteer-core so developers can drive a running Steel instance interactively:
cd repl
npm start # runs src/script.ts with tsx
Source: repl/README.md:1-15, repl/package.json:1-20. The repl intentionally depends on puppeteer-core (not full Puppeteer) because the browser is launched by the API process.
Casting, Navigation, and Context Tools
api/src/utils/casting.ts provides low-level helpers (navigatePage, getPageTitle, getPageFavicon) used by casting/CDP plugins to map incoming events to puppeteer-core calls and to normalize URLs before page.goto. api/src/utils/context.ts complements these by extracting storage state from every visited origin so it can be restored on the next launch Source: api/src/utils/casting.ts:1-50, api/src/utils/context.ts:1-60.
First-Party Automation Frameworks
Puppeteer and Playwright can be pointed at Steel by using the session's wsUrl (or debuggerUrl) as the browserWSEndpoint / connectOptions.wsEndpoint. The README links to dedicated guides for Puppeteer, Playwright (Node and Python), and Selenium integrations Source: README.md:160-200. For Selenium, Steel offers a drop-in compatible mode activated with isSelenium: true when creating a session, exposing a WebDriver-compatible endpoint Source: README.md:120-150.
The recorder extension lives under api/extensions/recorder/ and uses rrweb + @rrweb/packer to capture page activity for replay in the UI's rrweb-player Source: api/extensions/recorder/package.json:1-15, ui/package.json:10-50.
Common Failure Modes & Troubleshooting
Several community-reported issues map directly onto this surface area:
- Fingerprint generation failures โ Self-hosted
steel-browser-apiv0.5.3 with[email protected]can fail to generate a consistent fingerprint on Chrome 146 at fixed 1920x1080. The temporary workaround is to setSKIP_FINGERPRINT_INJECTION=1; the upstream issue is tracked in #302 and #295 Source: issue #302, issue #295. npm run devboot failure โ AReferenceError: File is not definedinsideundiciwhen running the API locally; the typical resolution is to run on Node 22+ (which is also enforced viaenginesinapi/package.json) Source: issue #230, api/package.json:1-30.- Feature gaps โ Community requests (#123, #144) highlight the desire for more documentation on advanced features and for cluster-level request routing to the node hosting a given session. The README confirms that all session-aware operations today are scoped to a single API instance Source: issue #123, issue #144.
When in doubt, the Swagger UI at /documentation and the Scalar reference at /scalar reflect the live schema defined by the modules cited above Source: api/package.json:30-60.
See Also
Source: https://github.com/steel-dev/steel-browser / Human Manual
Plugin System, Chrome Extensions & Anti-Detection
Related topics: Overview & System Architecture, Sessions, Quick Actions & Browser Integrations, Deployment, Configuration & Troubleshooting
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: Overview & System Architecture, Sessions, Quick Actions & Browser Integrations, Deployment, Configuration & Troubleshooting
Plugin System, Chrome Extensions & Anti-Detection
Overview
Steel Browser is an open-source browser API that combines three extensibility surfaces into a single stack:
- A Node/TypeScript plugin system that lets developers hook into the browser and CDP lifecycle.
- A Chrome extension loader that can ship custom extensions (e.g., the bundled
steel-recording-extension) into the launched Chrome instance. - An anti-detection layer built around
fingerprint-generatorandfingerprint-injector, paired with stealth helpers to reduce automated-traffic signals.
The README summarises this as "Anti-Detection: Includes stealth plugins and fingerprint management" and "Extension Support: Load custom Chrome extensions for enhanced functionality" (README.md:55-63).
The API package exposes these surfaces as named subpath exports so they can be consumed independently of the running server (api/package.json:9-35):
| Subpath | Purpose |
|---|---|
@steel-browser/api/plugin | Public plugin authoring entrypoint (steel-browser-plugin.ts) |
@steel-browser/api/cdp-plugin | Base class for CDP-layer plugins (services/cdp/plugins/core/base-plugin.ts) |
@steel-browser/api/logger | Browser-side logger plugin (plugins/logging/browser-logger) |
@steel-browser/api/storage | Log storage interface used by instrumentation plugins |
@steel-browser/api/browser | Browser type definitions |
Plugin System Architecture
The plugin stack is split into two layers:
- CDP plugins โ run inside the Node process, attached to Chrome DevTools Protocol sessions via
BaseCDPPlugin. The class contract and manager orchestration live underapi/src/services/cdp/plugins/core/(api/package.json:13-19). - Browser-context plugins โ ship JavaScript that runs inside the page via Puppeteer's
evaluateOnNewDocument. The bundledinstallMouseHelperutility inapi/src/utils/browser.tsis a representative example: it injects a cursor overlay guarded by a frame check so it only runs on top-level windows (api/src/utils/browser.ts:38-89).
A typical flow when a session starts looks like the diagram below.
flowchart LR
Client -->|HTTP /v1/sessions| API[Fastify API]
API --> PM[PluginManager]
PM -->|attach| CDP[CDP Plugins<br/>BaseCDPPlugin]
PM -->|launch hook| Browser[Browser Plugins<br/>browser-session.ts / browser.ts]
Browser -->|evaluateOnNewDocument| Page[Target Page]
PM -->|load flags| FG[fingerprint-generator<br/>fingerprint-injector]
FG --> PagePlugin Lifecycle Hooks
The lifecycle is event-driven. Recent releases have stabilised the hook contract:
- v0.5.3-beta introduced
onSessionStart,onBeforeSessionEnd, andonAfterSessionEndas first-class plugin hooks (Release v0.5.3-beta). - v0.5.0-beta allowed
onBrowserReadyto return a Promise, letting plugins await async setup before the browser is handed to the caller (Release v0.5.0-beta). - v0.5.2-beta added the ability for plugins to override the disconnect handler (Release v0.5.2-beta).
- v0.4.3-beta improved plugin launch hook timing and added fingerprint override support (Release v0.4.3-beta).
Plugins authored against this contract implement BaseCDPPlugin from services/cdp/plugins/core/base-plugin.ts and are registered through PluginManager in services/cdp/plugins/core/plugin-manager.ts (api/src/services/cdp/plugins/core/base-plugin.ts).
Chrome Extension Support
Steel can load arbitrary Chrome extensions into the launched Chrome instance, which is essential for capabilities like DOM recording and content scripts. The repository ships one reference extension:
api/extensions/recorder/โsteel-recording-extensionusesrrweband@rrweb/packerto capture DOM mutations for later replay (api/extensions/recorder/package.json:1-18).
Extensions are bundled with Webpack and shipped at runtime alongside the API container. The REPL package (@steel-browser/repl) demonstrates the consumption side: it uses puppeteer-core to connect to the CDP WebSocket exposed by the API and drive the browser programmatically (repl/README.md:1-15, repl/package.json:1-23). The same REPL entrypoint can be reused by any extension-driven workflow that needs CDP-level access.
Anti-Detection: Fingerprinting & Stealth
Anti-detection in Steel rests on two pinned dependencies:
| Package | Pinned version | Role |
|---|---|---|
fingerprint-generator | 2.1.82 | Generates consistent browser fingerprints (UA, screen, locale, hardware) |
fingerprint-injector | 2.1.82 | Applies the generated fingerprint to every launched context |
Both are listed in api/package.json as runtime dependencies (api/package.json:73-110). The fingerprint pipeline is invoked from the launch path and is overridable by plugins โ see the v0.4.3-beta fingerprint override support note in Release v0.4.3-beta.
Known Anti-Detection Failure Modes
The community has surfaced two related bugs that operators should be aware of when self-hosting:
- Issue #295 โ
Failed to generate a consistent fingerprint after 10 attempts. Reported againststeel-browserandsteel-browser-apiimages; the browser never launches and the container becomes unhealthy. - Issue #302 โ Same root cause but triggered specifically by Chrome 146 at a fixed
1920x1080viewport, forcing operators to setSKIP_FINGERPRINT_INJECTIONas a workaround.
The mitigation pattern documented in those threads is to disable fingerprint injection via the SKIP_FINGERPRINT_INJECTION environment variable when the pinned [email protected] cannot produce a consistent profile for the requested viewport/UA combination.
Security note: A coordinated vulnerability disclosure is currently open against the project (Issue #311) via VulnCheck. Operators tracking anti-detection or extension behaviour should watch that issue for remediation guidance.
Failure Modes & Operational Tips
| Symptom | Likely Cause | Mitigation |
|---|---|---|
ReferenceError: File is not defined on npm run dev (Issue #230) | Node version older than what undici expects File to be globally defined | Use Node โฅ 22 (matches engines in repl/package.json:18-22) |
Failed to generate a consistent fingerprint after 10 attempts (Issue #295) | [email protected] cannot match the requested UA/viewport combination | Set SKIP_FINGERPRINT_INJECTION=1 or adjust the requested viewport (Issue #302) |
| Extension not visible in launched Chrome | Extension not built or not copied into the container image | Run npm run build inside api/extensions/recorder/ (api/extensions/recorder/package.json:10-12) |
| Custom Chrome binary ignored | CHROME_EXECUTABLE_PATH set to a path that does not exist | getChromeExecutablePath() only warns and falls back to /usr/bin/chromium (api/src/utils/browser.ts:3-22) |
See Also
- README.md โ high-level feature overview and deployment options.
- Release v0.5.3-beta โ most recent plugin hook additions.
- Release v0.4.3-beta โ plugin launch hook timing and fingerprint override support.
- Issue #144 โ community request for cluster/session-affinity routing, relevant when scaling plugin state across nodes.
Source: https://github.com/steel-dev/steel-browser / Human Manual
Deployment, Configuration & Troubleshooting
Related topics: Overview & System Architecture, Sessions, Quick Actions & Browser Integrations, Plugin System, Chrome Extensions & Anti-Detection
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: Overview & System Architecture, Sessions, Quick Actions & Browser Integrations, Plugin System, Chrome Extensions & Anti-Detection
Deployment, Configuration & Troubleshooting
This page covers the operational side of the steel-browser project: how to run the API, the UI, and the REPL; how to tune the platform through environment variables; and how to recover from the most common failure modes reported by the community.
Overview
steel-browser is shipped as a multi-package workspace. Three services make up a working installation:
- API โ a Fastify-based Node service that manages Chrome sessions, proxies CDP traffic, and exposes the REST + WebSocket surface used by the Python and Node SDKs. Source: api/package.json
- UI โ a Vite + React debugging console that lists live sessions, replays recorded sessions via
rrweb-player, and provides a Swagger / Scalar reference browser. Source: ui/package.json - REPL โ a small Puppeteer-based script that connects over CDP for adโhoc scripting. Source: repl/package.json
The default public ports are 3000 for the API and 9223 for the CDP endpoint, with the UI dev server bound to 5173 by default. Source: README.md
flowchart LR Client[SDK / curl / Puppeteer] -->|HTTPS :3000| API[Fastify API] Client -->|WSS :9223| CDP[Chrome DevTools Protocol] API --> Browser[Headless Chrome] UI[Vite UI :5173] -->|OpenAPI proxy| API REPL[repl/src/script.ts] -->|WS :9223| CDP
Deployment Options
Quick Deploy (managed / one-click)
The README documents three hosted paths so a working instance can be brought up without a local toolchain:
| Method | Surface | Source |
|---|---|---|
GHCR combined image (ghcr.io/steel-dev/steel-browser) | API + UI in one container | README.md |
| Railway one-click | API + UI on Railway | README.md |
| Render one-click | API + UI on Render | README.md |
For Steel Cloud, the same steel-sdk is reused against a managed endpoint by changing baseURL (Node) or base_url (Python). Source: README.md
Docker (self-hosted)
A minimal self-hosted run uses the prebuilt image and exposes both ports:
docker run -p 3000:3000 -p 9223:9223 ghcr.io/steel-dev/steel-browser
The image's entrypoint, api/entrypoint.sh, bootstraps the API process and prepares the recorder extension (which is built from api/extensions/recorder/package.json via npm run prepare:recorder). Source: api/package.json
Local development
Each package has its own scripts. The API supports hot reload through tsx watch, the UI through Vite, and the REPL through tsx:
# API
cd api && npm run dev # tsx watch src/index.ts
# UI
cd ui && npm run dev # vite --host 0.0.0.0
# REPL
cd repl && npm start # tsx ./src/script.ts
Source: api/package.json, ui/package.json, repl/README.md
Configuration
Configuration is exclusively environment-driven, parsed in api/src/config.ts using dotenv. The full schema lives in api/.env.example and the root .env.example.
| Variable (selected) | Default | Purpose |
|---|---|---|
PORT | 3000 | API HTTP port. Source: api/src/config.ts |
CDP_PORT | 9223 | Chrome DevTools Protocol WebSocket port. Source: README.md |
STEEL_API_KEY | _empty_ | Bearer token for incoming REST/WS requests. Source: api/.env.example |
PROXY_URL | _empty_ | Upstream proxy chained into the browser via proxy-chain. Source: api/package.json |
SKIP_FINGERPRINT_INJECTION | false | Disables stealth/fingerprinting at launch. Source: api/.env.example |
OPTIMIZE_BANDWIDTH | false | Reduces traffic between API and browser (added in v0.4.2). Source: GitHub release v0.4.2-beta |
SCRAPE_EVAL_HEAVY | _unset_ | Enables heavier evaluation test path. Source: api/package.json |
Logging uses pino and pino-pretty and is configured through the same file. Source: api/package.json
Troubleshooting
The following failure modes appear repeatedly in the issue tracker and are directly addressable from configuration.
Browser fails to launch with fingerprint errors
Self-hosted containers on Chrome 146 at a fixed 1920x1080 viewport throw Fingerprint error during generation: Failed to generate a consistent fingerprint after 10 attempts and the container becomes unhealthy. The root cause is a mismatch between the pinned [email protected] and the new Chrome version. Two workarounds are used in the wild:
- Set
SKIP_FINGERPRINT_INJECTION=trueto bypass stealth and restore startup. Source: Issue #302, Issue #295 - Upgrade the
fingerprint-generator/fingerprint-injectorpair to a version that supports the new UA string, then rebuild the image.
`ReferenceError: File is not defined` during `npm run dev`
undici (a transitive dependency) references the File Web API, which is missing in Node < 18. Both api/package.json and repl/package.json declare "engines": { "node": ">=22.0.0" } (the API itself requires modern Node for the dev experience). Source: Issue #230. Use Node 20+ LTS (22+ recommended) and a clean node_modules install.
Recorder extension missing
The session recorder relies on a webpack build of the rrweb extension that is not produced during npm install. It is built on demand by npm run prepare:recorder (called automatically by npm run dev). Source: api/package.json. In Docker, api/entrypoint.sh performs the same step during image build; a missing recorder usually means the build step was skipped or its output pruned.
Session affinity and clustering
There is no built-in cross-node session routing: a session ID is valid only on the node that owns the Chrome process behind CDP_PORT. Multi-node deployments must front the cluster with a sticky router keyed on the session id returned by /v1/sessions. Source: Issue #144.
Security disclosures
The project runs a coordinated vulnerability disclosure program. Report suspected issues privately before opening a public ticket. Source: Issue #311.
Diagnostics checklist
GET /healthand the Swagger UI at/documentationto confirm the API is up. Source: README.md- Inspect
pinologs (ordocker logs <container>) for fingerprint, proxy, and CDP errors. - From the REPL, connect directly to
ws://host:9223to isolate API problems from browser problems. Source: repl/README.md - Re-run
npm test(Vitest) insideapi/to catch regressions introduced by configuration changes. Source: api/package.json
See Also
- README.md โ high-level features, deploy buttons, and SDK pointers
- api/src/config.ts โ authoritative list of environment variables
- api/.env.example โ documented defaults
- repl/README.md โ CDP debugging scripts
- GitHub releases โ changelog for flags such as
OPTIMIZE_BANDWIDTHand fullscreen
Source: https://github.com/steel-dev/steel-browser / Human Manual
Doramagic Pitfall Log
Source-linked risks stay visible on the manual page so the preview does not read like a recommendation.
May increase setup, validation, or first-run risk for the user.
May increase setup, validation, or first-run risk for the user.
May increase setup, validation, or first-run risk for the user.
May increase setup, validation, or first-run risk for the user.
Doramagic Pitfall Log
Found 11 structured pitfall item(s), including 3 high/blocking item(s). Top priority: Installation risk - Installation risk requires verification.
1. Installation risk: Installation risk requires verification
- Severity: high
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/steel-dev/steel-browser/issues/302
2. Installation risk: Installation risk requires verification
- Severity: high
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/steel-dev/steel-browser/issues/295
3. Installation risk: Installation risk requires verification
- Severity: high
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/steel-dev/steel-browser/issues/230
4. Installation risk: Installation risk requires verification
- Severity: medium
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: identity.distribution | https://github.com/steel-dev/steel-browser
5. Capability evidence risk: Capability evidence risk requires verification
- Severity: medium
- Finding: README/documentation is current enough for a first validation pass.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: capability.assumptions | https://github.com/steel-dev/steel-browser
6. Maintenance risk: Maintenance risk requires verification
- Severity: medium
- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: evidence.maintainer_signals | https://github.com/steel-dev/steel-browser
7. Security or permission risk: Security or permission risk requires verification
- Severity: medium
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: downstream_validation.risk_items | https://github.com/steel-dev/steel-browser
8. Security or permission risk: Security or permission risk requires verification
- Severity: medium
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: risks.scoring_risks | https://github.com/steel-dev/steel-browser
9. Security or permission risk: Security or permission risk requires verification
- Severity: medium
- Finding: Project evidence flags a security or permission risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/steel-dev/steel-browser/issues/311
10. Maintenance risk: Maintenance risk requires verification
- Severity: low
- Finding: issue_or_pr_quality=unknownใ
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: evidence.maintainer_signals | https://github.com/steel-dev/steel-browser
11. Maintenance risk: Maintenance risk requires verification
- Severity: low
- Finding: release_recency=unknownใ
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: evidence.maintainer_signals | https://github.com/steel-dev/steel-browser
Source: Doramagic discovery, validation, and Project Pack records
Community Discussion Evidence
These external discussion links are review inputs, not standalone proof that the project is production-ready.
Count of project-level external discussion links exposed on this manual page.
Open the linked issues or discussions before treating the pack as ready for your environment.
Community Discussion Evidence
Doramagic exposes project-level community discussion separately from official documentation. Review these links before using steel-browser with real data or production workflows.
- Coordinated Vulnerability Disclosure - steel-browser - github / github_issue
- [[BUG] Fingerprint generation fails for Chrome 146 at fixed 1920x1080, fo](https://github.com/steel-dev/steel-browser/issues/302) - github / github_issue
- [[QUESTION] how to fix this bug ,npm run dev](https://github.com/steel-dev/steel-browser/issues/230) - github / github_issue
- [[BUG] Self-hosted steel-browser-api fails with "Failed to generate a con](https://github.com/steel-dev/steel-browser/issues/295) - github / github_issue
- Release v0.5.3-beta - github / github_release
- Release v0.5.2-beta - github / github_release
- Release v0.5.1-beta - github / github_release
- Release v0.5.0-beta - github / github_release
- Release v0.4.5-beta - github / github_release
- Release v0.4.4-beta - github / github_release
- Release v0.4.3-beta - github / github_release
- Release v0.4.2-beta - github / github_release
Source: Project Pack community evidence and pitfall evidence