// OPENBOX DOCS
Configuration
Configure environment values, local state, and application settings.
OpenBoxGL reads configuration from three places, in order: the process environment, discovered .env files, and persisted application settings (the Settings dialog). This page documents each source, the exact variables, and the validation limits applied when settings are saved.
Configuration sources
| Source | When it is read | Precedence |
|---|---|---|
| Process environment | At startup and on demand (os.environ) | Highest |
Discovered .env files | bootstrap_env at Web UI startup, lazily before some lookups | Middle; never overrides an existing environment value |
| Persisted settings | library.json -> settings | Lowest for credentials; the only store for UI settings |
A .env file sets an environment variable only when that variable is not already set, so the process environment always wins. Unreadable or non-UTF-8 .env files are skipped silently; an optional .env must never abort startup.
.env discovery order
env_config.discover_env_files checks these roots in order and loads every .env found:
- The
OPENBOX_DATA_DIRyou passed in (used as an extra root). - The parent of the data directory.
- The current working directory.
- The application directory (next to
web_app.py). - Your home directory (
~/.env). ~/.config/openbox-game-launcher/.env.
Values already in the environment are never overridden by .env. The template lives at .env.example in the repository. Put real secrets in ~/.env or ~/.config/openbox-game-launcher/.env only, never in a tracked file.
Environment variables
Data and process behavior
| Variable | Meaning |
|---|---|
OPENBOX_DATA_DIR | Data directory. Read at import time, before .env bootstrap; must be exported in the shell, desktop entry, or systemd unit before launch. Defaults to ~/.local/share/openbox-game-launcher. |
OPENBOX_SAFE_MODE | Any non-empty value (conventionally 1) disables plugin execution and the webhook dispatcher for the whole process. Exposed as settings.safe_mode. |
APPIMAGE | Set automatically when running from an AppImage; the updater refuses to install without it. Exposed as settings.appimage. |
OPENBOX_ALLOW_HTTP_WEBHOOKS | Set to 1 to allow plain-HTTP webhook URLs. Required only for trusted local test targets; HTTPS is the default and safer. |
Credentials (all optional)
| Variable | Used by | Aliases |
|---|---|---|
RETROACHIEVEMENTS_USERNAME | RetroAchievements matching and progress | RA_USERNAME, OPENBOX_RA_USERNAME |
RETROACHIEVEMENTS_API_KEY | RetroAchievements web API | RA_API_KEY, RETROACHIEVEMENTS_KEY, OPENBOX_RA_API_KEY |
EMUMOVIES_USERNAME | EmuMovies media downloads | OPENBOX_EMUMOVIES_USERNAME |
EMUMOVIES_PASSWORD | EmuMovies media downloads | OPENBOX_EMUMOVIES_PASSWORD |
GITHUB_TOKEN | GitHub release API rate limit for update checks | GH_TOKEN, OPENBOX_GITHUB_TOKEN |
IGDB_CLIENT_ID | IGDB metadata provider (Twitch developer app) | — |
IGDB_CLIENT_SECRET | IGDB metadata provider (Twitch developer app) | — |
Each credential lookup checks the aliases in order using env_value() from env_config.py — it iterates through the listed names for a variable and uses the first non-empty value found. If an empty string is returned for any required variable, the route returns a specific 400 error naming exactly which variable is missing. For example, IGDB requires both IGDB_CLIENT_ID and IGDB_CLIENT_SECRET; without either the IGDB routes return 400 {"error":"Set IGDB_CLIENT_ID and IGDB_CLIENT_SECRET in ~/.env to use IGDB."}. Without RetroAchievements credentials, the /api/ra/* routes return 400 {"error":"Configure RetroAchievements first."}.
Credentials supplied through the Settings dialog are persisted in the data directory (retroachievements.json, emumovies.json, settings.json for Gameyfin) with owner-only permissions (0o600 via secure_text_write). The API and diagnostic log redact the values, but the files themselves are plaintext.
Persisted settings
The Settings dialog saves into library.json under settings. The save handler (web_app._save_settings_locked) validates each field before committing; an invalid value aborts the whole save with a 400 error. Keys must exist in the settings_schema.py registry: unknown keys are dropped with a diagnostic log warning rather than persisted. The full key list is exposed by GET /api/settings. Notable validated limits:
| Setting | Default | Validation |
|---|---|---|
watch_folders | [] | List of at most 50 absolute, existing directories; duplicates removed |
screensaver_seconds | 90 | 0 (off) or between 30 and 3600; values 1-29 are rejected |
controller_map | {} | Actions limited to play, back, favorite, random, page_left, page_right, pause, menu; button numbers 0–31 |
progress_automation_enabled | false | Boolean; enables/disables automatic progress changes |
progress_automation_play_minutes | 30 | 0 to 100,000 — minutes before marking Playing |
progress_automation_idle_days | 30 | 0 to 3,650 — days before marking Paused |
progress_on_first_play | "Playing" | Must be a known progress status |
welcome_completed | false | Boolean — hides the welcome wizard |
image_group | "cover" | One of cover, background, screenshot, clear_logo, fanart, banner, icon, box_back, box_spine, box_3d, title_screen |
badge_visibility | Most badges shown | Subset of favorite, installed, missing_media, saves, documents, versions, storefront, achievements, highscores, progress, rating, broken, portable, controller |
cloud_folder | "" | Absolute, existing path for mounted-folder statistics sync |
storefront_auto_import | All off | Object with boolean keys: steam, heroic, lutris, gameyfin |
auto_import_media_types | All types | Subset of cover, background, screenshots — applied during import-time media jobs |
media_download_limit | 0 (unlimited) | 0 to 10,000 |
region_priority | (default list) | Non-empty ordered list — ranks which regional media to prefer |
video_priority | snap, theme, trailer, recording | Subset of video_snap, video_theme, video_trailer, video_recording, video |
library_music | "" | Path to existing audio file; empty disables Big Box library BGM |
video_bgm_mix | false | Boolean — lower music volume when mixing with video audio |
bigbox_mode | "stage" | One of stage, hybrid, coverflow |
attract_mode_seconds | 90 | Seconds of idle before screensaver/attract mode triggers |
bigbox_startup_video | "" | Empty string (disabled) or path to startup video file |
bigbox_shutdown_commands | [] | At most 25 commands; run on entering Big Box (see note below) |
startup_commands | [] | At most 25 commands; run after server binds |
shutdown_commands | [] | At most 25 commands; run on graceful exit |
track_session_history | true | Boolean — when false, sessions still track but history isn't recorded |
backup_on_close | false | Boolean — creates save backups when session ends |
save_backup_limit | 10 | 0 to 500 — oldest archives trimmed after each backup |
tracking_mode | "default" | One of default, process, original_process, folder, process_name |
tracking_delay | 0 | 0 to 600 seconds before tracking starts after spawn |
tracking_frequency | 2.0 | 0.5 to 60 seconds between poll checks |
apply_perf | "auto" | One of off, auto, always — whether TDP limits apply |
auto_close_store_clients | false | Boolean — close Steam/Heroic/Lutris clients after a session ends |
obs_auto_attach | true | Boolean — auto-attaches latest OBS recording to game |
obs_recording_path | "" | Absolute, existing path override; empty uses discovery |
dynamic_play_button | true | Boolean — shows animated PLAY state |
custom_field_defs | [] | Up to 20 fields; each 50 options max |
platform_categories | Built-in mapping | Platform-to-category overrides (Nintendo, Sony, Microsoft, Computer, Arcade, Adventure, Other) |
list_columns | Defaults | Capped at 12 columns per platform or global view |
library_view | "grid" | Current persistent view preference |
locale | "en" | "en" only in 0.9.0; localization returns in a future release. Unknown locales fall back to English |
hidden_sidebar_sections | [] | Capped at 20 entries |
tray_enabled | false | Boolean — shows system tray icon |
minimize_to_tray | false | Boolean — minimizes to tray instead of closing |
show_playlist_actions | true | Boolean — show add/remove playlist buttons |
gameyfin_url | "" | Prepends http:// when no scheme present; must resolve |
gameyfin_username | "" | Stored as plain text alongside url and password |
gameyfin_password | "" | Empty value leaves stored password unchanged; otherwise persisted with 0o600 |
gameyfin_install_dir | "" | Absolute path; created if missing, rejected if symlink or non-existent. Empty by default; the UI shows a ~/Games/Gameyfin placeholder |
gameyfin_provider | "" | Provider label; falls back to first available |
ludusavi_backup_path | "" | Optional absolute path for Ludusavi JSON output |
ui_window | "app" | One of app, browser — whether the UI opens chrome-less or in a browser tab; overridden by --app-window / --no-app-window |
Two naming details worth knowing:
bigbox_shutdown_commandsis misnamed: the commands run when Big Box is entered, not when it is left. Theentering: falsesignal from the UI is ignored by the handler.attract_mode_secondsis the screensaver delay the Big Box screensaver actually reads; it falls back toscreensaver_secondswhen unset, and the Settings dialog keeps both fields with the same fallback.
Partial saves merge with existing settings: keys you omit are preserved, and concurrent partial saves of different keys do not lose updates (covered by the API sweep tests). An empty gameyfin_password in a save leaves the stored password unchanged.
Values consumed at startup
These are read once during process startup and require a restart to change:
OPENBOX_DATA_DIR(data directory and state store path)server.token/server.port(per-launch, deleted on exit).envbootstrap (performed once per process)startup_commands(run after the server binds, viarun_configured_commands)- Profile merging from emulator definition packs (
merge_profiles_from_definitions) at startup
shutdown_commands run on graceful exit. Both command lists execute with shlex.split and a new session; failures are logged and skipped, never fatal.
Security notes
- Public examples must use placeholders. Never commit
.env,server.token,retroachievements.json,emumovies.json, or library exports. - Keep
server.token, provider credentials, and webhook secrets private. The diagnostic log redacts values matching token/password/secret/API-key/authorization patterns, but a.envfile is plaintext. - Restart OpenBoxGL after changing values consumed at process startup.
The authoritative sources are .env.example, env_config.py, the settings validation in web_app.py, and the Settings dialog.