Skip to content

Guides

Configuration

  • v0 · latest
  • 6 min read
  • Updated Sep 29, 2026

Every setting of BrowserHive is a key that you can set in three places: an environment variable, the config file, or a CLI flag. This page explains how they combine. The configuration reference lists every key with its type, default and constraints.

Lowest to highest. Rightmost wins.

defaults < environment variables < browserhive.config.json < CLI flags

When a key comes from more than one source, the startup log says which value won:

config: maxSessions=8 (cli) shadows config-file=4, env=2

browserhive config show prints the effective value and source of every key, and the dashboard’s System page shows the same table. Secrets such as authTokens and otelHeaders are always shown as <redacted>. A value the config file reads from an environment variable names it: (config-file via $OTLP_HOST) (see References).

Each key has one camelCase name; the other spellings are derived from it:

Key CLI flag Environment variable Config file
maxSessions --maxSessions 8 BROWSERHIVE_MAX_SESSIONS=8 "maxSessions": 8
sessionLease --sessionLease 2h BROWSERHIVE_SESSION_LEASE=2h "sessionLease": "2h"
allowInsecureBind --allowInsecureBind BROWSERHIVE_ALLOW_INSECURE_BIND=true "allowInsecureBind": true

Rules:

  • CLI flags are case-sensitive camelCase. --maxsessions or any kebab-case spelling is an unknown flag; the error suggests the camelCase spelling.
  • Booleans: --admin sets true; --admin=false or --noAdmin sets false. --admin false (with a space) is not accepted, so a boolean never swallows the next argument.
  • Durations take ms, s, m, h or d (30m, 2h). A bare number is milliseconds.
  • Sizes take B, KiB, MiB, GiB, KB, MB or GB. A bare number is bytes.
  • Lists are comma-separated on the CLI and in env (--otelSignals traces,logs), and JSON arrays in the file.
  • Maps are k=v,k2=v2 on the CLI and in env, and JSON objects in the file.

Configuration problems stop the process before it binds a port or opens the database, with exit code 64 and a message that names the source:

browserhive: unknown flag '--maxSession'. Did you mean '--maxSessions'? Run 'browserhive --help'.
browserhive: invalid value for --sessionLease: '2 hours'. Expected a duration like '2h', '30m', '90s', '500ms', or an integer of milliseconds.
browserhive: BROWSERHIVE_PORT is set but empty. Unset it or provide a value.
browserhive: 'otelHeaders' in /etc/browserhive/browserhive.config.json references {env:OTLP_TOKEN}, but OTLP_TOKEN is not set. Set it, or write a default as {env:OTLP_TOKEN:-<value>}.

Unknown BROWSERHIVE_* environment variables and unknown keys in the config file fail the same way. An empty value is an error, not “unset”. Some combinations are rejected too, for example humanize=true with stealth=off, or admin=true with transport=stdio. The full list is under cross-field rules.

Check a configuration without starting the server:

Terminal window
browserhive config validate

browserhive.config.json is plain JSON (no comments). BrowserHive uses the first file it finds:

  1. --config <path> (or BROWSERHIVE_CONFIG). A missing file here is an error.
  2. ./browserhive.config.json in the current directory.
  3. <data-dir>/browserhive.config.json.

Relative paths inside the file resolve against the file’s directory. A config file found in the data directory may not change dataDir.

For editor completion, write the JSON Schema next to your file and reference it:

Terminal window
browserhive config schema > browserhive.schema.json
{
"$schema": "./browserhive.schema.json",
"transport": "http",
"host": "127.0.0.1",
"port": 9876,
"admin": true,
"auth": "token",
"persistence": "persistent",
"maxSessions": 6,
"sessionLease": "2h",
"attentionTimeout": "6h",
"minAttentionWait": "30m",
"stealth": "standard",
"humanize": true,
"vault": "bitwarden",
"blocklist": "./blocklist.txt",
"blocklistWatch": true,
"retentionDays": 14,
"retentionBytes": "2GiB",
"logLevel": "info,sessions=debug",
"logFormat": "auto",
"otel": true,
"otelEndpoint": "http://127.0.0.1:4318",
"otelServiceName": "browserhive-lab"
}

The same schema is published in this repository as config.schema.json.

If the file contains a token in authTokens, keep it readable only by you (chmod 600); doctor warns otherwise. Better, keep the token out of the file: "authTokens": "ci-runner:{env:CI_TOKEN}" reads it from the environment (see References), and doctor has nothing to warn about.

A string in browserhive.config.json can read an environment variable. The file can then be checked in and shared, while secrets and per-machine values come from the environment:

{
"otel": true,
"otelEndpoint": "http://{env:OTLP_HOST:-127.0.0.1}:4318",
"otelHeaders": { "Authorization": "Bearer {env:OTLP_TOKEN}" },
"authTokens": ["ci-runner:{env:CI_TOKEN}"],
"maxSessions": "{env:MAX_SESSIONS:-4}"
}
Write Gets
{env:NAME} The value of NAME. Startup stops with an error if NAME is not set or is empty.
{env:NAME:-default} The value of NAME, or default when NAME is not set or is empty.
{{env:NAME}} The literal text {env:NAME}.
  • A reference can be the whole value or part of it, including array elements and object values such as the headers in otelHeaders. The result is read exactly as the key’s environment variable would be: "maxSessions": "{env:MAX_SESSIONS}" accepts 8 or unbounded, and "authTokens": "{env:BH_TOKENS}" accepts a comma-separated list. For numbers and booleans, write the reference as a string: "port": "{env:PORT}".
  • Each value is read once. A variable whose own value contains {env:…} is used as it is, never expanded again.
  • Only the config file is expanded. On the command line and in BROWSERHIVE_* variables your shell already does this (--authTokens "ci-runner:$CI_TOKEN"); BrowserHive leaves {env:…} there untouched and prints a warning.
  • env is the only kind of reference, written in lower case. Text that looks like another kind, such as {file:/run/secrets/token} or {ENV:NAME}, stops startup with a message that says how to keep it literal: double the braces, {{file:/run/secrets/token}}. ${env:NAME}, the OpenTelemetry Collector’s spelling, stops startup with a hint to drop the $. Other braces, such as {trace_id} in otelTraceUrlTemplate, are left alone.
  • On Windows, variable names are case-insensitive, as they are in the OS.
  • A relative path that comes from a reference, as in "blocklist": "{env:BLOCKLIST}", resolves against the config file’s directory, like every path in the file.

Every place that shows the configuration names the variable:

config: otelEndpoint=http://collector.internal:4318 (config-file via $OTLP_HOST) shadows env=http://127.0.0.1:4318
config: otelHeaders=<redacted> (config-file via $OTLP_TOKEN) shadows env(otel)=<redacted>
  • browserhive config show prints config-file via $OTLP_HOST in the SOURCE column, and config-file via $MAX_SESSIONS (default) when the default was used.
  • browserhive config show --json and GET /api/v1/system/config add refs (the variables and whether each default was used) and template (the value as written in the file).
  • On the dashboard’s System page, a $NAME chip sits next to the source. Select it to see whether the variable was set and the value as written. The Only values from references switch lists just those keys.
  • browserhive doctor counts the values that came from references and warns about each variable that was not set, so its default is in use.

Secrets stay hidden. For authTokens and otelHeaders, BrowserHive shows the variable’s name but never its value or the text around it in the file, and it scrubs the value from logs. The same happens for any key whose variable name contains a word such as token, secret, password, apikey or credential: for that run the key is shown as <redacted> everywhere, even its values from other sources. Error messages name the key, the file and the variable, not the line.

Key Default Purpose
transport http http or stdio
host, port 127.0.0.1, 9876 bind address, shared by MCP, API, WebSocket and dashboard
admin false dashboard, REST API, live view, traces
auth off token requires bearer tokens on /mcp and scopes sessions to their owner
persistence memory default for launch_session: memory, persistent, storage-state
vault off bitwarden enables credential injection
stealth standard off, standard or max; see also fingerprint and humanize
defaultChannel chromium the browser sessions use: the bundled chromium, or the installed chrome or edge (choosing the browser)
sandbox auto Chromium’s sandbox: auto wherever the machine allows it, on required (refuses to start otherwise), off never (security)
maxSessions derived from RAM concurrent session cap, or unbounded
publicUrl unset the address where you reach the dashboard from elsewhere (a Tailscale name, a reverse proxy, a tunnel); notification links use it (public address)
allowedHosts none extra Host names to accept, such as the name a reverse proxy forwards
sessionLease 2h idle sessions are closed after this long
blocklist unset URL blocklist file
dataDir OS default where state lives
logLevel, logFormat info, auto logging; logLevel accepts per-module levels like info,sessions=debug
recordToolResults full how much of each tool result is stored
otel, otelEndpoint false OpenTelemetry export

maxSessions defaults to min(floor(RAM in GiB / 1.5), 20). trace defaults to the value of admin, and fingerprint defaults to true only when stealth=max.

For a service manager (systemd EnvironmentFile, docker --env-file):

Terminal window
BROWSERHIVE_TRANSPORT=http
BROWSERHIVE_HOST=0.0.0.0
BROWSERHIVE_PORT=9876
BROWSERHIVE_AUTH=token
BROWSERHIVE_AUTH_TOKENS=ci-runner:REPLACE_WITH_32_PLUS_CHARS
BROWSERHIVE_ADMIN=true
BROWSERHIVE_DATA_DIR=/var/lib/browserhive
BROWSERHIVE_LOG_FORMAT=json
BROWSERHIVE_OTEL=true
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318

Standard OTEL_* variables are honoured below BROWSERHIVE_* ones; see the reference.

An agent can override some defaults for one session through launch_session arguments: persistence_mode, headless, channel, stealth, fingerprint, humanize, disable_evaluate, vault_enabled, context_options and launch_options. These are not configuration and never appear in config show. See launch_session.

Most keys need a restart. logLevel, logFormat and otelTraceUrlTemplate can be changed while the server runs (the log level from the dashboard’s System page or PATCH /api/v1/system/log-level).