Skip to main content
browser-use sends anonymized usage telemetry: model, steps, cost, timing, helper names, the URLs visited (without query strings), error messages and the final result. Never the task text, typed text, code or secrets. ANONYMIZED_TELEMETRY=false turns it off, for the library, the CLI and the MCP server:
Any value that does not start with t, y or 1 turns it off. Off means off: no event, no background thread, no file written. The events go to PostHog so we can see which models, browsers and helpers work, where runs spend their time and why they fail. There are no feature flags or remote settings: telemetry only sends, it never changes what the library does.

Never sent

  • The task text, follow-up tasks and extend_system_message. Where a URL, error message or result quotes the whole task, it is sent as <task>.
  • Text typed into pages.
  • The model’s messages and thinking, and partial results.
  • Code the model writes, and tracebacks (their frames quote the code). Repeated code is detected by a hash that never leaves the process.
  • sensitive_data values. Where one appears in a URL, error message or result, it is sent as <secret:name>.
  • API keys and credentials: sk-..., sk-ant-..., bu_..., AIza... and similar keys, JWTs, Bearer / Basic tokens and password=..., token=..., api_key=... values are sent as <credential>. Email addresses, anywhere, are sent as <email>.
  • Query strings and fragments, and a URL’s user, password and port. Hostnames that alone grant access (tunnels such as *.ngrok-free.app and *.trycloudflare.com, cloud IDE ports, Lambda function URLs, preview deploys) are sent as the provider’s pattern, not the name.
  • Page content: titles, HTML, screenshots, file names, js() expressions, cdp() parameters. The final result is sent, so text the agent extracted into it is too.
  • CDP endpoints. Only their kind (browser-use-cloud, localhost, private, public-other).
  • Paths and endpoints: never your base_url, user_data_dir or executable path.
  • Uncaught exceptions from your process. There is no exception autocapture.

What is sent

agent_event holds:
  • Install and environment: browser-use, Python, Pydantic AI and browser-harness versions; OS; whether it runs in Docker, CI or a notebook.
  • Configuration: model id and provider, reasoning, mode, max_steps, timeout, whether structured output, custom tools (their names), secrets (a count) or a custom workspace are used, and the task’s length.
  • Browser: the mode (cloud, chromium, chrome, cdp), keep-alive, cloud proxy country and timeout, domain restrictions (counts, never the domains) and start time.
  • Outcome: status, success, how the result was delivered, the exception class and the phase it happened in, the error messages and the final result (below).
  • Time: where the run spent it: browser start, model requests, cells, helpers, waits, compaction, shutdown.
  • Model: steps, requests, tokens, cost, calls per tool, retries by cause.
  • REPL: cells, cell errors by class, helper and CDP method counts and timings, imported module names, screenshots.
  • Browsing: the URLs visited (below), hostnames the agent navigated to, navigation and download counts, Chrome net error codes, CAPTCHA solver events, domain-restriction blocks.
  • Per step: for the first 50 and last 150 steps, timings, token counts, tool names, the helpers used and the hostname the step ended on.
The text fields, each scrubbed as in Never sent before it is cut: The other fields are numbers, bools, enums, hostnames, or names chosen by browser-use, the developer, Python or an installed package (model id, helper, tool, module, exception class, CDP method). A run whose process was killed (out of memory, SIGKILL, a notebook kernel restart) is reported the next time browser-use runs on that machine, with status crashed and only its configuration, step count and time. cli_event keeps the command, exit code, duration, helper names and counts, browser kind, client, and error_message: the exception line of the error, scrubbed, at most 300 characters. browser-harness’s own event would include the piped code, its output and the full error text; the browser-use CLI removes those before sending. mcp_server_event keeps the tool name, duration, whether it failed, the exception class and error_message: the exception’s message, scrubbed, at most 300 characters. Neither ever includes the code, its output or arguments.

How it is sent

  • A run never waits on the network. Recording is an in-memory counter; a background thread builds the event, gzips it and posts it to https://eu.i.posthog.com/batch/ with Python’s standard library.
  • At process exit, events still queued are handed to a short-lived background process, so exit does not wait either.
  • Files, all under ~/.config/browseruse (BROWSER_USE_CONFIG_DIR moves it), and only while telemetry is on: device_id; telemetry/inflight/ for a run in progress (deleted when its event is sent); telemetry/outbox/ for events not sent yet (at most 20 files and 512 KB, deleted after 7 days).
  • The browser-use CLI sends cli_event to the same place under the same id, and creates no browser-harness install id.

Identity

One anonymous id per machine: BROWSER_USE_DEVICE_ID if set, else a random id stored in ~/.config/browseruse/device_id. If that file can’t be written, a hash of the machine’s MAC address and hostname. PostHog derives a location from the request IP. BROWSER_USE_TELEMETRY_INTERNAL=1 marks events as internal (is_internal). We set it in our own tests and evals, so they don’t count as usage.