Monitoring & metrics
What to watch on a running daemon: the health probes, the metrics endpoint and its probe states, the opt-in Prometheus surface, and the event stream as the live signal.
Three surfaces, and they answer different questions. /health says the process is up. /v1/metrics says what it is doing. The event stream says what just happened.
Health probes
| Path | Auth | Answers |
|---|---|---|
/health | none | The process is serving. |
/health/live | none | Liveness, for an orchestrator. |
/health/ready | none | Readiness. |
All three sit outside the auth layer, which is what makes them usable as a monitor probe.
Do not probe for a file. runtime.json lives in the data directory and is only removed by an orderly stop, so a crashed or wedged daemon leaves it exactly where it was. A probe watching that file reports healthy forever, including for a process that is frozen. Ask /health instead.
The metrics endpoint
GET /v1/metrics, behind the bearer token, answers with the resource picture:
- how many browsers are running, against the configured concurrency
- the configured memory budget and what is used
- host memory, CPU and GPU figures
- a per-profile breakdown
It is served from a background sampler, so the request path probes nothing and the numbers are at most one sampling interval old. The cadence is [observability] sample_interval_ms, 3000 by default.
Probe states
Every measured value is paired with one of three states:
| State | Meaning |
|---|---|
measured | This is a reading. |
unsupported | This platform cannot report it. |
unavailable | It should be readable and was not, right now. |
This is why "zero" and "we could not read this" never look alike. A monitor that treats a missing GPU reading as 0 percent draws a flat green line for a machine it has stopped measuring, which is the worst possible failure for a dashboard.
Prometheus
Off by default. [observability] enable_prometheus turns it on and prometheus_bind places it, on loopback by default.
It is unauthenticated plaintext, on a separate listener, not behind the API's token. The daemon warns loudly if you bind it publicly. Firewall it, or scrape it over a private network.
The live signal
Polling metrics tells you about the machine. The event stream tells you about the work: profiles starting, crashing and being refused, proxy checks, exit-guard verdicts, runs starting and finishing.
Three of those are worth an alert on any install:
profile_crashed, with its reasonpreflight_failed, which means a profile is configured in a way that cannot startexit_guard_changedmoving tosevered, which means a browser lost its address mid-session
Logs
RUST_LOG controls verbosity, and log_json switches to machine-readable lines, which is what you want wherever something other than a person reads them.
Crash reporting is off by default and needs both a switch and a destination. On an anti-detect product, telemetry nobody asked for is the kind of surprise that costs the customer relationship rather than just producing a report.
Watching disk
Three things grow: profile directories, activity stills, and video files.
| What | Bounded by |
|---|---|
| Activity stills | [runs] shots_max_gb and shots_max_age_days. |
| Artifacts | [mcp] artifact_quota and artifact_ttl_secs. |
| Videos | Nothing automatic. GET /v1/videos/storage says what they cost. |
| Profiles | Nothing automatic. A browser directory grows the way any browser's does. |
Next
- Events: the frames to build an alert on.
- Configuration: the settings named here.
- Troubleshooting: what the numbers mean when they go wrong.