BrowserGym Core
Gymnasium environment for building and evaluating LLM-driven web agents in a real Chromium browser.
Repository Health
Technical Analysis
browsergym-core is the foundational package of BrowserGym, ServiceNow Research’s framework for training and evaluating web agents. It wraps Playwright-driven Chromium browsing in a Gymnasium-compatible environment (BrowserEnv), exposing page state as a marked DOM snapshot, merged accessibility tree, and screenshot, and accepting either a configurable high-level action set (click, fill, scroll, tab management, drag-and-drop) or raw Python code that agents can address by stable element bid.
Installed standalone, browsergym-core only registers the openended task — an agent-driven browsing session that starts at a given URL and optionally exposes a chat interface. The benchmark-specific packages in the same monorepo (browsergym-miniwob, browsergym-webarena, browsergym-workarena, browsergym-visualwebarena, browsergym-assistantbench) build on top of it by subclassing AbstractBrowserTask and calling register_task(), so every benchmark shares one observation format, one action space, and one Playwright browser-lifecycle implementation.
What You Get
- A Gymnasium-compatible
BrowserEnvthat manages a headless (or headed) Playwright Chromium browser end-to-end: launch, context, page, and teardown. - Structured per-step observations: marked DOM snapshot, merged accessibility tree with element
bids, screenshot, focused element, and chat history. - A high-level action set (click, fill, scroll, hover, drag-and-drop, tab/window management, keyboard input) plus a raw Python-code action escape hatch.
- The
openendedtask out of the box — point an agent at any starting URL with an optional interactive chat loop. - An
AbstractBrowserTaskbase class andregister_task()helper for turning new benchmarks into first-class Gym environments. - A built-in MCP server (
browsergym.utils.mcp_server) for exposing the browser environment to MCP-speaking clients.
Common Use Cases
- Training or evaluating an LLM-based web agent against a live, real browser instead of a scripted mock.
- Building a new benchmark by subclassing
AbstractBrowserTaskand reusing the observation/action machinery. - Running an interactive, chat-driven open-ended browsing session to debug an agent’s action policy step by step.
- Powering downstream BrowserGym packages (MiniWoB++, WebArena, VisualWebArena, WorkArena, AssistantBench) that only add task definitions on top of this core runtime.
Under The Hood
Architecture BrowserEnv (env.py, ~690 lines) is the central Gymnasium gym.Env subclass, orchestrating a global sync_playwright() instance (browsergym/core/init.py) into a browser to context to page pipeline; each reset() launches the task via a task_entrypoint (an AbstractBrowserTask subclass frozen with kwargs by register_task() in registration.py) which calls setup(page) to navigate and return a goal, and each step() executes an agent’s action, either through the configurable HighLevelActionSet in action/highlevel.py, mapped to Python via execute_python_code in action/base.py and action/python.py, or a raw callable, before running the observation pipeline (_pre_extract/_post_extract, extract_merged_axtree, extract_dom_snapshot, extract_screenshot in observation.py) and delegating pass/fail scoring back to the task’s validate(). Task definition, environment orchestration, action parsing, and observation extraction sit in clearly separated modules behind a narrow AbstractBrowserTask contract that every sibling benchmark package in the monorepo depends on without touching env.py directly.
Tech Stack browsergym-core targets Python 3.9+ and is built with hatchling plus hatch-requirements-txt (pyproject.toml), pinning playwright==1.44 for browser automation, gymnasium>=0.27 for the RL-style env interface, numpy for array-typed observation spaces (spaces.py’s AnyBox/Anything/Float/Unicode), beautifulsoup4 and lxml for auxiliary DOM parsing, Pillow for screenshot handling, pyparsing for the action-set docstring parser (action/parsers.py), and mcp[cli] to expose a Model Context Protocol server (utils/mcp_server.py). The package ships no web framework of its own — its “server” is a live headless-Chromium instance controlled directly via Playwright’s sync API — and is versioned dynamically via hatch’s version hook pointing at src/browsergym/core/init.py.
Code Quality Tests live under tests/core/ (test_task.py, test_observation.py, test_actions_python.py, test_actions_highlevel.py, test_gym_envs.py, test_registration.py) and run in CI via pytest against a real Playwright-launched Chromium, alongside a dedicated black-formatting check job, signalling a genuine testing culture built on real-browser integration tests rather than pure mocks. Core modules use type hints and docstrings throughout (env.py, task.py, observation.py), dataclasses in action/highlevel.py, and custom exceptions such as MarkingError in observation.py rather than swallowing errors silently. No mypy/pyright configuration was found, so type checking stays documentation-level rather than enforced, and there is no dedicated linter beyond black formatting.
API Design The public surface is intentionally narrow: implement AbstractBrowserTask’s setup/validate (and optional cheat/teardown), call register_task(), and the task becomes a standard gym.make()-able environment with no further wiring. The HighLevelActionSet exposes browser actions as plain, docstring-annotated Python functions an agent can call directly or express as parsed text, which keeps the action interface consistent across every benchmark package while still allowing raw Python/Playwright code as an escape hatch for edge cases the high-level API doesn’t cover.