How to build seleniumbase-rs from source, which features cost what, and how to
run it in a container. For writing and running tests with it, start with
Getting started; for working on the crate, see
CONTRIBUTING.md.
What you need#
Pick your system below and paste its box into a terminal. Each box installs what
every build needs: Rust 1.99 (the repository’s rust-toolchain.toml selects it),
a C compiler, and Google Chrome. The extras for single features come after.
Nothing here needs Python.
In a hurry? Give the prompt below to your AI coding assistant and let it install and check everything.
Let an AI assistant do it#
Paste this into an AI coding assistant that can run commands on your machine (Claude Code, Cursor, Copilot and the like):
Set up this computer to build and test the Rust library seleniumbase-rs (https://github.com/MustCodeAl/seleniumbase-rs). Follow its docs/building.md (“What you need”) for my operating system:
- Find out which OS and CPU this is. Install what is missing, and only that: Rust through rustup (the repo’s rust-toolchain.toml picks 1.99), a C compiler (Xcode command line tools / build-essential / Visual Studio 2022 Build Tools with C++), and Google Chrome. Use Homebrew on macOS, apt or dnf on Linux, winget on Windows. Ask me before anything that needs an administrator password, and don’t change system security settings yourself.
- Clone the repository (or use this folder if it is the repository) and run
cargo build --bin sbrs, thensbrs doctor(target/debug/sbrs doctor, ortarget\debug\sbrs.exe doctoron Windows). - Run the checks and say how many tests passed and failed:
cargo fmt --all -- --check,cargo clippy --all-targets --features "mcp-server test-util" -- -D warningsandcargo test --features "mcp-server test-util". - Only if I ask for a feature, install its extras from the “Extras for single features” part of docs/building.md (s3, gui, the Tauri example).
Don’t edit any code. Finish with a short list of what you installed, the versions, and anything that failed with its first error line.
Optional browsers and drivers (drivers otherwise download by themselves):
Safari is built in. Allow automation once, then turn on Safari ▸ Develop ▸ Allow Remote Automation:
Google Chrome on x86-64:
Chromium instead (also on arm64), and Firefox:
A display for headed browsers on a server:
Edge comes with Windows. Firefox:
Open a new terminal after installing, so the new programs are on the PATH.
Check it worked#
The last line prints the browsers it found and whether their drivers match.
Extras for single features#
Most features need nothing more: tui, mcp-server, turso, playwright,
azure, gcp, full-tracing, test-util, ocr, visual, plugins and the
built-in plugins (plugin-shield, plugin-block-resources, plugin-crx, or
plugins-builtin for all of them). The rest:
s3OpenSSL on Linux
s3 needs OpenSSL on Linux (nothing on macOS and Windows):
guiDesktop input and native dialogs
gui (desktop input and native dialogs). On macOS nothing to install; at
run time allow the program under System Settings ▸ Privacy & Security ▸
Accessibility. On Windows nothing. On Debian and Ubuntu:
The stealth scraping layerMoved out in 0.3.0
The stealth scraping layer (the former scrape and impersonate features)
moved in 0.3.0 to its own workspace,
seleniumbase-rs-stealth.
Its BoringSSL build needs CMake and libclang (and NASM and LLVM on Windows);
those instructions live in that repository now. This crate needs none of them.
The Tauri exampleNode LTS
The Tauri example (examples/tauri-profile-manager) needs Node LTS (brew install node, winget install OpenJS.NodeJS.LTS). On Windows it also uses
WebView2, which comes with Windows 10 and 11. On Debian and Ubuntu:
Repository toolsmdBook, Python, just, cargo-deny
mdBook for the docs (brew install mdbook or cargo install mdbook), Python 3.10+ for the parity tables in tools/parity, and
just and cargo-deny (brew install just cargo-deny or cargo install just cargo-deny). With mise, mise install sets up Rust,
Python, Node, mdBook, just and cargo-deny in one step.
What has been built where#
| System | Built and run |
|---|---|
| macOS (Apple Silicon) | Everything |
| Debian 12 arm64, in Docker | The default build and the test features |
| Windows 11 x64 | The default build, the test features, the real-browser tests and the Tauri example |
The Linux gui and Tauri package lists come from the CI configuration, which
has not been able to run (see Operating systems).
Build#
The repository is a Cargo workspace of two packages: the library
seleniumbase-rs at the root, and the command line seleniumbase-rs-cli in
crates/cli, which holds both binaries. A project that depends on the library
compiles none of the command-line crates. sbrs is always built; sbrs-mcp
needs the mcp-server feature, which the command-line package turns on by
default together with pdf. To put the binaries on your PATH:
Neither package is published to crates.io, so cargo install seleniumbase-rs-cli
does not work; build from a checkout, install from git as below, or add the
library as a git dependency.
Install without a checkout#
Three ways to get sbrs and sbrs-mcp (the package seleniumbase-rs-cli) onto
your PATH without cloning the repository. None of them uses crates.io.
The prebuilt archives do not exist yet. They come from
.github/workflows/release.yml, which builds sbrs and sbrs-mcp for
aarch64-apple-darwin, x86_64-apple-darwin, x86_64-unknown-linux-gnu,
aarch64-unknown-linux-gnu and x86_64-pc-windows-msvc when a v* tag is
pushed, and attaches them to that GitHub release. GitHub Actions is locked on
this repository by a billing problem, so the workflow has not run: the
releases v0.1.0 to v0.2.0 have no binary assets. Until it runs, cargo binstall and mise’s github: backend find nothing to download; the commands
that build from source (cargo install --git, mise’s cargo: backend and
Homebrew) work today.
Each release archive (seleniumbase-rs-v<version>-<target>.tgz, .zip on
Windows) holds these at its root:
warp
SHA256SUMS lists the checksum of every archive.
cargo binstall#
No archives yetcargo-binstall downloads the
release archive for your system instead of compiling. crates/cli/Cargo.toml
tells it where the archives are ([package.metadata.binstall]). With --git it
reads that manifest from the repository, so no crates.io entry is needed:
It installs both binaries. Two things to know: --git takes the default
branch, so it fetches the release whose version the branch’s Cargo.toml
names, and that release must have its archives; and the metadata turns off the
compile fallback, because cargo-binstall would compile from crates.io, where the
crate is not. cargo-binstall installs no completions: write them with sbrs completions <shell> (see the CLI page).
mise#
mise has two backends that fit.
The github: backend picks the archive for your system and puts both binaries on PATH:
Until the release archives exist, mise reports “No versions found” for it.
To build from the git tag now, the cargo: backend runs cargo install --git
(Rust 1.99 must be on PATH, for example with mise use -g rust@1.99). The
repository has one package with binaries, seleniumbase-rs-cli, so cargo finds
it by itself, and it builds sbrs-mcp too (features = ["tui"] adds the
terminal UI):
The binaries moved from the package seleniumbase-rs to seleniumbase-rs-cli
after v0.4.0. For a tag up to v0.4.0, add features = ["mcp-server"] to get
sbrs-mcp.
mise installs no completions for these backends either; its per-tool
postinstall option can run sbrs completions zsh into your completions folder.
Homebrew#
Works todayThe tap builds from the release’s source and installs the completions and the Warp workflows as well (macOS and Linux):
cargo install from git#
Works todayWhat the methods above do when there is no archive, by hand:
That builds sbrs and sbrs-mcp; add --no-default-features for sbrs alone,
without PDF text extraction. For a tag up to v0.4.0 the binaries are in the
package seleniumbase-rs:
cargo install --git https://github.com/MustCodeAl/seleniumbase-rs --tag v0.4.0 --features mcp-server --locked.
Features#
No feature of the library is on by default, so a plain build is small and pulls in
none of the desktop or cloud stacks. The command-line package
seleniumbase-rs-cli turns pdf and mcp-server on by default and forwards
tui, gui and turso to the library; the rest of the features below belong
to the library. Build the library alone, with its own defaults, with
cargo build -p seleniumbase-rs.
| Feature | Adds | Note |
|---|---|---|
mcp-server | the sbrs-mcp binary (rmcp) | needed for the MCP servers |
tui | sbrs commander, the terminal UI | without it the command prints a hint and exits with status 2 |
gui | native OS dialogs and GUI automation | links GTK and X11 on Linux |
playwright | the Playwright-compatible mode (rustwright) | |
s3, azure, gcp | uploading reports and artifacts | |
turso | ResultStore, ProfileVault, sbrs report | an embedded database |
full-tracing, error-backtrace | extra tracing, a backtrace on every error | for debugging |
test-util | the scripted mock browser | for tests that drive pages without Chrome |
ocr | ocr::Ocr, text read from screenshots and PNG images (ocrs, rten, image) | pure Rust; downloads two models (about 12 MB) on first use, see Reading text from the screen |
visual | visual::VisualBaseline and BaseCase::assert_visual_match: screenshots compared with a baseline by structural similarity, with a diff image on a mismatch (image-compare, image with PNG only) | pure Rust; brings rayon; see Visual regression testing |
Combine them with --features "mcp-server tui". The features scrape and
impersonate were removed in 0.3.0; see Stealth Scraping.
Check your build#
Container#
The Dockerfile builds sbrs with locked dependencies in a Rust 1.99 stage and
copies it into a debian:bookworm-slim image with Chromium and its driver. It
runs as a non-root user (sbrs) and has no EXPOSE, because sbrs is a
command-line tool. The driver in /usr/bin is linked as
downloaded_drivers/chromedriver in the working directory, which is where the
WebDriver engine looks first, so the image needs no network to start a browser.
- On a machine with little memory, limit Cargo’s parallelism in the build:
docker build --build-arg CARGO_BUILD_JOBS=2 -t seleniumbase-rs . - The arguments after the image name are
sbrsarguments.--headlesscomes before the subcommand.sbrs openandsmokealso readSB_HEADLESS(and the otherSB_*variables;--headlessbeats the variable), and without one of them Chromium fails in a container for lack of a display. - Drop
chromium-driverfrom theDockerfileif you only use the pure CDP engine (and then drop theln -sstep that links it).
Verified on an Apple-silicon Mac with Docker (so linux/arm64, Debian 12,
Chromium 154.0.8037.92): the build succeeds in about four minutes with two Cargo
jobs and gives a 1.19 GB image; --help and doctor exit with status 0, and
doctor finds /usr/bin/chromium and a chromedriver of the same major version;
the smoke command above exits with status 0 with no network. sbrs install in
the image downloads an aarch64 chromedriver (Chrome for Testing publishes
linux-arm64 from Chrome 153 on).
Run the tests in a container#
docker/Dockerfile.verify is a throwaway image for the test suite: the Rust
toolchain, Debian’s Chromium and chromedriver, and Xvfb. docker/verify-linux.sh is its entry
point: it copies the read-only checkout mounted at /src to /work, so tests that
write beside their sources cannot touch your tree, and then runs your command there.
The build output lives in a named volume (about 4.4 GB when these runs still built
the stealth layer too), and the Cargo registry in another.
The doc tests need -- --test-threads=2 in 4 GB: with the default of one thread per
CPU, the linker was killed for lack of memory in 66 of them. Give the container more
memory instead if you have it.
The image sets CI=true and SB_NO_SANDBOX=1 (Chromium cannot start its sandbox as
root in a container, and the real-browser tests read CI) and SB_HEADLESS=true.
The results, and what they showed, are under
Verified on Linux. Remove everything when you are
done:
Adding a [[bin]], [[example]], [[bench]] or [[test]] to Cargo.toml
also needs a line in the Dockerfile skeleton step, or the image build fails;
tests/dockerfile_skeleton.rs checks it.
Build time and disk#
A cold build compiles a large dependency tree, and a development target/
directory with the test, bench and check artifacts grows past 10 GB. To keep
rebuilds cheap:
- Install
sccacheand set[build] rustc-wrapper = "sccache"in~/.cargo/config.toml; it needsCARGO_INCREMENTAL=0to cache anything. It adds its own cache directory (limit its size) and does not shrinktarget/. - On a machine with little memory, keep
CARGO_BUILD_JOBSlow and run one cargo command at a time; cargo serialises builds in the same target directory.
Several checkouts of this repository (for example git worktrees) must not share
one CARGO_TARGET_DIR: they overwrite each other’s compiled library. Do not cargo clean a target directory that other builds are using.
Build the documentation#
The generated docs/parity.md is not edited by hand: just parity-docs
rebuilds it from parity/api.toml.
The Docs7 site#
The same pages also publish as a Docs7
site. docs/docs.json is its configuration, and its navigation follows
docs/SUMMARY.md.
Regenerate the navigation
Do this after changing the table of contents:
Preview it locally
Needs Node. Run it, then open http://localhost:4317:
Publish
Open the Docs7 tab of your Context7 teamspace, choose Add New
Site, pick this repository, and set the branch to main and the folder to
docs. Every push to main then rebuilds the site.
Operating systems#
What differs between macOS, Linux and Windows when you build and run
seleniumbase-rs. The CI workflow (.github/workflows/ci.yml) is set up to
build and test on all three, but has not been able to run yet; day-to-day
development and the project’s own checks run on macOS (Apple silicon), so macOS
is the best-trodden path, and Windows 11 was checked by hand (see
Windows). The test suite was also run
on Linux (arm64, Debian 12, Chromium 154) in a container; what passed, and what
was not run, is under Verified on Linux.
The packages each system and each feature needs, with the commands that install them (Homebrew, apt, dnf, winget), are in Building and installing.
Which Chrome it finds#
The library looks in the usual install locations, and you can always name one:
- Looked at:
/Applications/Google Chrome.app,~/Applications/Google Chrome.app, Chromium, Chrome Canary - Override:
SB_CHROME_BINorCHROME_BIN
- Looked at:
google-chrome,google-chrome-stable,chromiumandchromium-browserin/usr/bin(and/snap/bin/chromium), then the same names on thePATH - Override:
SB_CHROME_BIN,CHROME_BINorCHROMIUM_BIN
- Looked at:
Program Files,Program Files (x86)and the per-userGoogle\Chrome\Application\chrome.exe - Override:
SB_CHROME_BINorCHROME_BIN
For the WebDriver engine, sbrs install downloads the chromedriver that matches
your Chrome’s major version, and CHROMEDRIVER_PATH points at one you already
have. The pure CDP engine (sb_cdp) needs no chromedriver on any system.
The WebDriver engine looks for downloaded_drivers/chromedriver in the working
directory first and uses it when its major version fits the browser; otherwise it
downloads the matching Chrome for Testing
driver. That download is linux64 on x86-64 Linux and linux-arm64 on arm64
Linux, which Chrome for Testing publishes from Chrome 153 on; for an older Chrome
on arm64, or any other Linux architecture, the error says that no build is
published and where to put a driver. A driver from your distribution works the
same way: link it into that folder, as the repository’s Dockerfile does, and no
network is needed:
Firefox and Edge#
A Firefox session starts geckodriver and an Edge session msedgedriver,
as Python SeleniumBase does. Each is looked for in downloaded_drivers/ (right
in it, or in the newest geckodriver-v<version>/ or
msedgedriver-<version>/ folder there) and then on the PATH, so a Homebrew or
distribution geckodriver is used as it is. When none is found:
| Driver | Downloaded from | Which build |
|---|---|---|
| geckodriver | github.com/mozilla/geckodriver/releases | The newest release; one geckodriver drives a range of Firefox versions, so it is not matched to Firefox. sbrs get geckodriver 0.36.0 pins one. |
| msedgedriver | msedgedriver.microsoft.com | The newest build for the installed Edge’s major version (LATEST_RELEASE_<major>_<OS>), or the stable one when Edge cannot be found. A driver on disk or on the PATH for another Edge major version is replaced; with_driver_version pins one. |
The archives (tar.gz for geckodriver on Linux and macOS, zip otherwise) are
capped at 64 MB, unpacked without writing outside their folder, and made
runnable the way chromedriver is: the execute bit, and on macOS no quarantine
flag and, if the system kills the driver as it starts, a new ad-hoc signature.
Edge is looked for at /Applications/Microsoft Edge.app on macOS,
Microsoft\Edge\Application\msedge.exe under Program Files,
Program Files (x86) and the per-user folder on Windows, and
microsoft-edge, microsoft-edge-stable or /opt/microsoft/msedge/msedge on
Linux. Microsoft publishes no msedgedriver for arm64 Linux.
The session’s options go in moz:firefoxOptions (headless, arguments,
preferences, the user agent and locale as preferences, browser_binary_path as
the Firefox program and user_data_dir as -profile) and ms:edgeOptions (the
same options Chrome gets). Chrome-only settings such as extensions, mobile
emulation and the CDP and UC modes have no Firefox
equivalent and are not sent; the session proxy is not passed to Firefox either.
macOS#
Best-trodden path- A freshly written or replaced executable is slow the first time. macOS
scans it on first run, which can take seconds. The library writes a replaced
chromedriver as a new file because macOS kills a signed binary that is
overwritten in place; if a driver is “killed” or refused, run
sbrs installagain and see Common problems. - Gatekeeper and quarantine. A browser or driver downloaded by another tool
can carry a quarantine flag; clear it with
xattr -d com.apple.quarantine <file>if macOS refuses to open it. - Tests that fake
javaor other scripts must run the script once before timing it, for the same first-run reason. - Memory. On an 8 GB machine keep
CARGO_BUILD_JOBSlow and run one cargo command at a time.
Linux#
Run in a container: arm64, Debian 12-
Install a browser from your distribution (
chromiumand, for the WebDriver engine,chromium-driveron Debian and Ubuntu) or use Google Chrome’s own package. The repository’sDockerfileshows the Debian setup. -
Running as root or in a container usually needs
--no-sandbox. The WebDriver engine always passes it on Linux. For the pure CDP engine setSB_NO_SANDBOX(it is read as set or not set:SB_NO_SANDBOX=0also turns the sandbox off), or callLaunchOptionsBuilder::no_sandbox(true). The real-browser tests of this repository readCIinstead and pass--no-sandboxwhen it is set.Warning--no-sandboxweakens Chrome’s isolation, so use it only in a container you control. -
No display. Run headless (
SB_HEADLESS=true, whichsbrs openand the other browser commands read, or--headlessbefore the subcommand; see Headless and headed browsers). To see a window on a server, or to run the few tests that need a headed Chrome (the measurement tools), run under a virtual display such as Xvfb. StartXvfbin the background and exportDISPLAY;xvfb-runcan wait forever for a signal that a background process ignores. Theguifeature (native dialogs and GUI automation) links GTK and X11 and is off by default; thetuifeature has no such requirement. -
Shared memory. In Docker, Chromium can crash under load with the default
/dev/shm; start the container with--shm-size=1g(general Chromium advice). -
Wayland. The
guifeature’s input automation targets X11; the project has not tested it under Wayland.
Verified on Linux#
Run on 2026-10-11 to 12 with docker/Dockerfile.verify and docker/verify-linux.sh
(commands in Building and installing).
The host was an Apple-silicon Mac, so the containers were
linux/arm64 on Debian 12 (bookworm) with Rust 1.99 and Chromium
154.0.8037.92 from Debian’s chromium and chromium-driver packages. Cargo ran
with CARGO_BUILD_JOBS=2 in a container limited to 4 GB.
These runs predate 0.3.0: the feature set still had scrape, so the counts below
include the tests of the stealth layer, which has since moved to
seleniumbase-rs-stealth
(its impersonate runs, the measured-persona checks and a flaky JA3 test fixed
then are no longer part of this crate).
| Run | Result |
|---|---|
Library tests, --features "mcp-server test-util scrape" | 2112 passed, 0 failed, 16 ignored |
| The other test binaries of that feature set (68) | 406 passed, 0 failed, 114 ignored (the real-browser tests, ignored by default) |
| Doc tests, same features | 182 passed, 0 failed, 10 ignored |
Real Chromium 154: browser_smoke and 17 *_chrome binaries, one at a time with -- --ignored --test-threads=1 | 112 passed, 0 failed (headless, except the 2 of scrape_capture_chrome, now in seleniumbase-rs-stealth, which ran headed on a virtual display) |
cargo test --test dockerfile_skeleton | 9 passed |
What the runs showed:
- A real bug, fixed: the chromedriver download used the x86-64
linux64build on every Linux machine, so an arm64 container failed with “chromedriver exited as it started”. It now asks forlinux-arm64:sbrs installin the arm64 image fetches an aarch64 executable, andbrowser_smoke(7 tests) starts Chromium through a driver it downloaded that way. - Container limits, not bugs: the doc tests need
-- --test-threads=2in 4 GB (with eight threads the linker was killed for lack of memory in 66 of them); a headed browser needs a display, which Xvfb gives; Chromium needs--no-sandboxas root.
Not run: x86-64 Linux, Google Chrome (only Debian’s Chromium), other Linux
distributions, the playwright, gui, tui, s3, azure, turso and gcp
features, stealth_audit_network (it needs outside sites), playwright_chrome, and
the macOS-only driver_repair_macos. Whether the pure CDP engine starts as the
non-root sbrs user of the image with the sandbox on was not tried.
Windows#
Checked by hand: Windows 11Status: on Windows 11 x64 (Rust 1.99, Chrome 154 and 155, Edge 155, Firefox
153) formatting, clippy, the whole test suite and the real-browser tests pass,
and the Tauri example builds its .msi and setup .exe. (The stealth layer,
then the impersonate feature, built and passed there too; it now lives in
seleniumbase-rs-stealth
with its CMake, NASM and LLVM requirements.) Install steps:
Building and installing.
What works differently
- The Chrome and Edge version comes from the program file’s own version
(
chrome.exe --versionprints nothing on Windows). While an update waits for a restart, that is still the version that runs, so the right driver is fetched. - Download folders are given to Chrome as plain
C:\...paths. - Build in a short folder (
C:\src\seleniumbase-rs) if a deeptarget\path hits the 260-character limit. In Rust code, use raw strings for Windows paths.
Not there yet on Windows
- If the program that started a browser is killed, the browser can keep running (macOS and Linux end it; Windows needs a job object). A driver whose session fails, or that is dropped, is ended.
- The tests’ leftover-process checks list processes with
sysinfonow, so they run on Windows too, but they have not been run on a Windows PC yet. - Measured fingerprints exist for Chrome 155 on macOS only; the TLS and HTTP/2
tables refuse other systems with
NotMeasured.
WSL and remote machines#
Run the Linux steps inside WSL. A browser inside WSL has no display unless you
use WSLg or run headless. To drive a browser on another machine, run
sbrs-mcp or your tests there, or point the WebDriver engine at a
Selenium Grid (sbrs grid) with BrowserConfig::webdriver_url.
Check the setup on any system#
From an AI agent, the MCP tool diagnose_environment reports the same plus the
platform, the redacted SB_* settings and the output directory.