OpenEnv documentation

OpenApp Environment

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v0.8.0).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

OpenApp Environment

OpenApps Environment

A web application simulation environment for OpenEnv that wraps the OpenApps framework and BrowserGym.

Overview

Agents interact with simulated web apps (calendar, todo list, messenger, maps) through BrowserGym browser actions: click, fill forms, navigate, scroll and type.

OpenApps Demo

Quick Start

Build the image from envs/openapp_env/ (about 5.7 GB, it includes Chromium and OpenApps):

docker build -t openapp-env:latest -f server/Dockerfile .

The container runs two servers: OpenApps on port 5001 (internal) and the OpenEnv API on port 8000. You only talk to port 8000.

from openapp_env import OpenAppAction, OpenAppEnv

with OpenAppEnv.from_docker_image("openapp-env:latest").sync() as client:
    result = client.reset()
    print(f"Starting URL: {result.observation.url}")

    result = client.step(OpenAppAction(action_type="goto", url="http://localhost:5001/calendar"))
    result = client.step(OpenAppAction(action_type="click", bid="add-event-btn"))
    result = client.step(OpenAppAction(action_type="fill", bid="event-title-input", text="Team Meeting"))

    print(f"Reward: {result.reward}, Done: {result.done}")

Element IDs (bid) come from the observation’s axtree_txt. To use the async client, await OpenAppEnv.from_docker_image(...) instead of calling .sync().

A complete script is in examples/openapp_example.py:

python examples/openapp_example.py --mode docker --num-steps 20

With the container running (docker run -p 8000:8000 openapp-env:latest), the web UI is at http://localhost:8000/web and the API docs at http://localhost:8000/docs.

Environment Details

Action

OpenAppAction

action_typeRequired fields
clickbid (BrowserGym element ID)
fillbid, text
select_optionbid, value
gotourl
scrolldirection ("up" or "down")
send_keystext
noopnone

Observation

OpenAppObservation

  • html: current page HTML
  • url: current page URL
  • open_pages_urls, active_page_index: open tabs and the active one
  • axtree_txt: accessibility tree, with the element IDs to act on
  • screenshot: base64-encoded screenshot (optional)
  • app_state: state of the apps (calendar events, todos, messages, …)
  • task_info: {"task_name": ...} when the server was started with a task name
  • last_action_error: error message if the last action failed
  • metadata["cumulative_reward"]: reward accumulated over the episode

Reward

The environment wraps OpenApps in a generic BrowserGym task that never scores or ends an episode by itself. Each step returns:

  • -0.1 when the action fails or action_type is unknown
  • the BrowserGym task reward otherwise, which is 0.0 with the generic task

The episode ends after max_steps steps (default 50). For task-specific rewards, score the episode yourself from app_state. See the OpenApps documentation for its tasks.

Configuration

The environment connects to an OpenApps server that is already running, at OPENAPPS_URL (the Docker image sets it to http://localhost:5001). It doesn’t launch one itself.

To change the other settings, construct OpenAppEnvironment (in server/openapp_environment.py) yourself:

ParameterDefaultDescription
openapps_urlOPENAPPS_URLURL of the OpenApps server. reset() fails if OPENAPPS_URL is not set
headlessTrueRun the browser headless
task_nameNoneTask name, reported in task_info
apps_config{}App configuration
max_steps50Steps per episode

Running Without Docker

Install the environment and a browser, then start OpenApps from a clone of its repository (the pip package doesn’t ship launch.py and its Hydra configs):

pip install -e envs/openapp_env
playwright install chromium

git clone https://github.com/facebookresearch/OpenApps.git
cd OpenApps && uv sync
uv run launch.py                                      # headless
uv run launch.py browsergym_env_args.headless=False   # with a visible browser

In another terminal:

export OPENAPPS_URL=http://localhost:5001
python examples/openapp_example.py --mode local

The apps are also reachable in your browser at http://localhost:5001 (/calendar, /todo, /messages, /maps). The browser window is controlled by the OpenApps server, so start it with browsergym_env_args.headless=False to watch the agent.

Troubleshooting

  • Container did not become ready behind an HTTP proxy: set export NO_PROXY=localhost,127.0.0.1 and retry.
  • Container exits immediately: check docker logs <container-id>. Usually OpenApps failed to start (port conflict) or a dependency is missing (rebuild with --no-cache).
  • Connection refused to localhost:5001 in local mode: start the OpenApps server first and set OPENAPPS_URL.
  • Slow container: it runs Chromium and the web apps. Give Docker 6 GB or more of memory and keep headless=True.

Attribution

Citation

If you use this environment in your research, please cite both OpenEnv and OpenApps:

@article{ullrich2025openapps0,
  title   = {OpenApps: Simulating Environment Variations to Measure UI-Agent Reliability},
  author  = {Karen Ullrich and Jingtong Su and Claudia Shi and Arjun Subramonian and Amir Bar and Ivan Evtimov and Nikolaos Tsilivis and Randall Balestriero and Julia Kempe and Mark Ibrahim},
  year    = {2025},
  journal = {arXiv preprint arXiv: 2511.20766}
}
Update on GitHub