# Behavior traces — browser-use/browser-use

> Canonical page: https://codevetter.com/unpack/browser-use/behavior-traces

# Behavior traces — browser-use/browser-use

Scanned commit d8110c5ff87ccba887aaa726cdb780f2f84bef8d (2026-09-15). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

Three flows dominate. Startup brings up logging, the agent object, the browser process or cloud session, and the watchdog set before any model call. The primary step is a fixed phase sequence from DOM snapshot through LLM output to event-bus actions. Persistence is split across the in-memory AgentHistoryList, the on-disk file system and screenshots, optional conversation and GIF files, cookie storage state, and cloud event sync.
- Process startup for the library: importing browser_use runs setup_logging unless BROWSER_USE_SETUP_LOGGING=false, reading CONFIG log file paths, and monkeypatches asyncio BaseSubprocessTransport.__del__ to ignore 'Event loop is closed'. — [browser_use/__init__.py#L1-L43](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/__init__.py#L1-L43)
- Agent construction order after argument validation: resolve llm (DEFAULT_LLM via get_llm_by_name, else ChatBrowserUse), force flash_mode for provider browser-use, build BrowserSession if none was passed, assign task_id and session_id via uuid7str, create AgentState and AgentHistoryList, create the temp agent directory, then _set_file_system and _set_screenshot_service. — [browser_use/agent/service.py#L225-L301](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/agent/service.py#L225-L301) [browser_use/agent/service.py#L435-L453](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/agent/service.py#L435-L453) [browser_use/agent/service.py#L699-L744](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/agent/service.py#L699-L744)
- Browser startup order inside on_BrowserStartEvent: attach_all_watchdogs; if no cdp_url and use_cloud, CloudBrowserClient.create_browser and store cdpUrl with is_local False; else if local, dispatch BrowserLaunchEvent and read BrowserLaunchResult.cdp_url from LocalBrowserWatchdog; then connect() under _connection_lock with a 15s timeout; then dispatch BrowserConnectedEvent so storage restore finishes before start returns. — [browser_use/browser/session.py#L786-L888](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/browser/session.py#L786-L888) [browser_use/browser/watchdogs/local_browser_watchdog.py#L49-L63](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/browser/watchdogs/local_browser_watchdog.py#L49-L63)
- SecurityWatchdog.on_NavigateToUrlEvent runs before navigation and raises ValueError when _is_url_allowed is false. on_NavigationCompleteEvent sends blocked redirects to about:blank. on_TabCreatedEvent tries to close a disallowed new tab. block_ip_addresses uses ipaddress plus socket.inet_aton so non-standard IPv4 spellings cannot bypass the check. Empty allow and deny lists allow all URLs. — [browser_use/browser/watchdogs/security_watchdog.py#L35-L92](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/browser/watchdogs/security_watchdog.py#L35-L92) [browser_use/browser/watchdogs/security_watchdog.py#L138-L220](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/browser/watchdogs/security_watchdog.py#L138-L220)
- Primary step trace: step → wait_if_captcha_solving → _prepare_context → get_browser_state_summary → _check_and_update_downloads → _update_action_models_for_page → registry.get_prompt_description → MessageManager.prepare_step_state / maybe_compact_messages / create_state_messages → budget, replan, exploration, and loop nudges → _get_next_action → multi_act → _post_process → _finalize. — [browser_use/agent/service.py#L1035-L1231](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/agent/service.py#L1035-L1231)
- Inside multi_act, each action is executed through Tools.act. Actions registered with terminates_sequence=True (navigate, search, go_back) abort the rest of the queue, and a URL or target change after any action also aborts the remainder so later clicks are not applied to a stale DOM. — [browser_use/agent/service.py#L2728-L2758](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/agent/service.py#L2728-L2758) [browser_use/tools/service.py#L458-L461](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/tools/service.py#L458-L461) [browser_use/tools/service.py#L502-L506](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/tools/service.py#L502-L506)
- Initial URL handling: when directly_open_url is true, _execute_initial_actions runs the converted initial action list through multi_act before the LLM loop and stores that as history step 0 with a synthetic AgentOutput. The call is wrapped in wait_for(step_timeout) so a dead CDP socket cannot hang startup forever. — [browser_use/agent/service.py#L197-L199](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/agent/service.py#L197-L199) [browser_use/agent/service.py#L2575-L2592](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/agent/service.py#L2575-L2592) [browser_use/agent/service.py#L3284-L3330](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/agent/service.py#L3284-L3330)
- Done path: the done action returns ActionResult(is_done=True). _post_process logs the final result. _execute_step sees history.is_done(), optionally _judge_and_log, invokes register_done_callback, and run() breaks. On consecutive_failures past max_failures (plus one if final_response_after_failure) the loop stops without a successful done. — [browser_use/tools/service.py#L2012-L2045](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/tools/service.py#L2012-L2045) [browser_use/agent/service.py#L1244-L1252](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/agent/service.py#L1244-L1252) [browser_use/agent/service.py#L2484-L2497](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/agent/service.py#L2484-L2497) [browser_use/agent/service.py#L2609-L2633](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/agent/service.py#L2609-L2633)
- CLI startup trace: main → _dispatch. No args and a TTY prints _QUICKSTART and returns 0. Piped stdin is reassigned to a StringIO and passed to _run_browser_harness, which calls browser_harness.run.main. --mcp imports and runs the MCP stdio server. A NameError raised from executed <string> code is rewritten into an unknown-helper message and exit 2. — [browser_use/cli.py#L185-L202](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/cli.py#L185-L202) [browser_use/cli.py#L357-L458](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/cli.py#L357-L458)
- Cookie persistence trace: BrowserConnectedEvent triggers StorageStateWatchdog.on_BrowserConnectedEvent → _load_storage_state. On BrowserStopEvent / SaveStorageStateEvent it calls _save_storage_state. The watchdog is not attached at all unless storage_state or user_data_dir is configured. — [browser_use/browser/session.py#L1730-L1750](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/browser/session.py#L1730-L1750) [browser_use/browser/watchdogs/storage_state_watchdog.py#L49-L158](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/browser/watchdogs/storage_state_watchdog.py#L49-L158)
- Cloud sync auth is a device-code OAuth flow in DeviceAuthClient: POST /api/v1/oauth/device/authorize with scope 'read write', then poll /api/v1/oauth/device/token with grant_type urn:ietf:params:oauth:grant-type:device_code, storing access_token on CloudAuthConfig. — [browser_use/sync/auth.py#L87-L136](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/sync/auth.py#L87-L136) [browser_use/sync/auth.py#L157-L315](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/sync/auth.py#L157-L315)
- Rerun trace: load_and_rerun can substitute detected variables via _substitute_variables_in_history, then rerun_history walks stored actions, using detect_variables_in_history (element id, name, type, placeholder, aria-label, then value patterns) to name inputs. save_history dumps the filtered history to AgentHistory.json by default. — [browser_use/agent/service.py#L3905-L3915](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/agent/service.py#L3905-L3915) [browser_use/agent/variable_detector.py#L9-L149](https://github.com/browser-use/browser-use/blob/d8110c5ff87ccba887aaa726cdb780f2f84bef8d/browser_use/agent/variable_detector.py#L9-L149)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
