// OPENBOX DOCS
Interfaces and data
Understand OpenBoxGL interfaces, local state, and environment selection.
OpenBoxGL ships one UI over two hosts that share one local library. This page explains what you see, how the pieces fit together, and exactly where your data lives so you can back it up, move it, or diagnose problems.
One UI, two hosts
| Host | Entry point | What you see | Best for |
|---|---|---|---|
| Native window | openbox or openbox-native | A native WebKitGTK window rendering the same three-column workspace: filter sidebar, cover grid or list, detail pane | Default desktop use |
| Web UI | openbox --web or python3 web_app.py | The same UI in a chrome-less app window (falls back to your browser) | Development, debugging, REST API, Big Box mode |
Both hosts render the identical index.html, app.js, and app.css served by the loopback server, so there is no second presentation stack to drift. The native host is a small C shim that owns the window chrome and spawns the Python server as a child; it never contains application logic.
Native host
Starting openbox (or openbox-native) does three things in order:
- Acquires a single-instance lock; a second launch focuses the existing window and exits.
- Spawns
web_app.py --no-browseras a child and waits for it to writeserver.portandserver.token. - Opens a WebKitGTK window at
http://127.0.0.1:PORT/?token=..., restores the last window geometry, and registers awindow.openboxNativebridge for native dialogs, external opens, reveal, and window chrome.
On window close the host shuts the server down cleanly. When WebKitGTK is missing, the launcher prints an install hint and falls back to the system-browser app window, so no install bricks.
The bridge surface is window.openboxNative (native_host.c:1211-1541):
| Member | Purpose |
|---|---|
dialog(kind, opts) | Native file open/save dialogs (C handle_dialog) |
reveal(path) | Reveal a data/home-contained path in the file manager (containing folder only; never launches it) |
openExternal(target) | Open an approved external URL in the system handler |
windowAction(action) | Native window chrome actions (minimize, focus, geometry) |
onGamepad(callback) | Gamepad-input hook (no-op stub in the current host) |
Web UI
Running python3 web_app.py starts the loopback server directly and opens the same UI in a chrome-less app window (falling back to the default browser). Pass --no-browser to drive the API yourself.
The server is loopback-only, so nothing is reachable from the network. The URL carries the per-launch token in the query string; the API also accepts the same value as an X-OpenBox-Token header. When the server stops, both files are deleted. The keyboard launcher (scripts/openbox-launcher.sh) and openbox:// deep links read these two files to find and authenticate against the running server. See Command line and deep links for the full flag and URI reference.
Where data lives
The default data directory is ~/.local/share/openbox-game-launcher. Everything OpenBoxGL persists lives there:
| Path (inside the data directory) | Contents |
|---|---|
library.json | The library: games, profiles, history, settings, playlists, queue, notifications |
library.json.bak | Last-known-good copy, rewritten before every commit |
.library.json.lock | Cross-process lock file coordinating concurrent writes |
operations.json | Durable background operations and task lifecycle states |
setup_previews/ | Transient scan preview documents before commit |
server.token, server.port | Per-launch credentials for the running app; deleted on exit |
native-host.lock, window-geometry, native-host-flags | Native host single-instance lock, last window geometry, and tray flags |
backups/ | Library backup archives (OpenBoxBackup-*.zip) |
save-backups/ | Versioned per-game save backups with retention limits |
media/ | Downloaded artwork, screenshots, video, and metadata media, grouped by source (media/memories/ holds imported Memories gallery items, media/clips/ holds Record That captures) |
exports/ | Library export files (JSON/CSV); the newest 10 are kept (v1.8.0+) |
themes/ | Stock themes plus locally imported CSS themes |
plugins/ | Installed local plugin packages |
metadata/ | The synced LaunchBox Games Database file |
cache/ | Archive extraction and RetroAchievements working files |
media-queue.json | Pending media download jobs |
highscores/, bezels/ | MAME high-score exports and bezel downloads |
The library file itself is schema-versioned JSON with stable game IDs derived from game identity, never from list position. That is why playtime, queue entries, and save links survive reordering or deleting other entries.
When catalog synchronization is enabled, its immutable events live under <cloud_folder>/openbox-library-v3/ in the mounted folder you selected; they are separate from local library.json and never copy launch paths, commands, credentials, statistics, saves, or media.
Changing the data directory
Set OPENBOX_DATA_DIR in the process environment before starting OpenBoxGL:
OPENBOX_DATA_DIR=/mnt/library openbox
Two details matter:
- The variable is read at startup, before
.envbootstrap. Putting it inside a discovered.envfile is too late for this choice; export it in the shell, a desktop entry, or a systemd unit instead. - If the directory does not exist, it is created on first write. Migrate an existing library by moving the whole data directory, including
library.json, and pointing the variable at the new location; the sidecar, media, and backups should move with it.
Legacy data
When OPENBOX_DATA_DIR is not set and no library.json exists yet, OpenBoxGL looks for the legacy path ~/.local/share/launchbox-linux/library.json and copies it into the new data directory, so an earlier test install keeps its library.
Configuring credentials
Credentials and tokens can come from three places, in order: the process environment, discovered .env files, and persisted application settings (Settings dialog). The .env search order is an explicit OPENBOX_ENV_FILE path if set, the data directory and its parent, your home directory (~/.env), and ~/.config/openbox-game-launcher/.env. The current working directory is not searched. Values already in the environment are never overridden by .env.
Supported variables are documented in .env.example and Configuration; they cover RetroAchievements (RETROACHIEVEMENTS_USERNAME, RETROACHIEVEMENTS_API_KEY), EmuMovies, IGDB, and GITHUB_TOKEN for release-API rate limits. Keep these files private; the API and the diagnostic log redact the values, but a .env file itself is plaintext.
Security model
- The server binds to loopback and requires the session token on every request. Prefer the
X-OpenBox-Tokenheader for API calls you write; atokenquery parameter can leak into browser history and server logs. - Tokens, passwords, API keys, and authorization headers are redacted in the diagnostic log.
- Webhooks reject plain HTTP targets by default;
OPENBOX_ALLOW_HTTP_WEBHOOKS=1enables them for trusted local tests only. - No OpenBox account exists and no library data leaves your machine except what an integration you explicitly trigger sends. Statistics and catalog synchronization use only the mounted folder you choose; catalog sync is opt-in and keeps launch paths, commands, credentials, statistics, saves, and media local.
Backups and recovery
The state store writes atomically: it writes the backup copy from the temp file first, then swaps the primary into place, so a crash cannot pair a fresh primary with a stale backup. If the primary file ever fails to decode, OpenBoxGL preserves the original, raises a clear error, and recovery must be explicit. Restore paths and archive members are validated, symlink parents are rejected, and a pre-restore safety copy is created automatically.
Make a backup before major changes: Settings has a backup manager, and python3 web_app.py --backup creates an archive from the command line. See Data and recovery and Library backups.
Troubleshooting orientation
- App starts but no browser: run from a terminal and open the printed URL, or pass
--no-browserand drive the API yourself. - App starts but the library looks empty: check
OPENBOX_DATA_DIR; the server is reading a different directory than the one you edited. - Launch fails: the detail pane names the missing piece (executable permission, launch command, platform profile, or path). Check the diagnostic log for the backend's view.
Related: Configuration, Data and recovery, REST API, Troubleshooting.