A lightweight bridge that lets you control OBS Studio scene switching from TouchOSC (or any OSC controller) over the network. It runs silently in the system tray and uses almost no resources.
Built for Windows and Linux (see Building on Linux). macOS builds on request.
- OBS Studio 28+ with the built-in WebSocket server enabled (obs-websocket v5)
- Windows 10 or later
Download osc-obs-bridge.exe from the latest release and put it in a folder (e.g. C:\Program Files\osc-obs-bridge\).
Run the exe. Three things happen:
- Windows Firewall will ask to allow network access β click Allow. The bridge needs this to receive OSC messages from your tablet.
- A
config.jsonfile is created next to the exe with default settings - A red dot π΄ appears in your system tray (bottom-right of the taskbar β you may need to click the
^arrow to see it)
Right-click the tray dot and choose Open Config. This opens config.json in your text editor. You only need to change one thing:
Your OBS WebSocket password β find this in OBS under Tools > WebSocket Server Settings. Copy the password and put it in the config:
"obs_password": "your-password-here"Everything else should work automatically:
osc_listen_hostdefaults to"auto"which detects your machine's local network IPosc_send_hostdefaults to"broadcast"which sends responses to all devices on your network- Ports default to TouchOSC's defaults (9000/8000)
Tip: If auto-detection picks the wrong network interface (e.g. you have multiple NICs), check the log file to see which IP was detected, then set
osc_listen_hostto the correct IP manually. If you'd rather target a single tablet, setosc_send_hostto the tablet's IP instead of"broadcast".
Save the config file, then right-click the tray dot and choose Reload Config. If everything is set up correctly, the dot turns green π’.
In TouchOSC, open the connection settings π and go to the OSC tab. Set up a new connection or update an old one:
- Host: Tap Browse β the bridge should appear as
osc-obs-bridge. Selecting it auto-fills the host and send port. If it doesn't appear, enter the bridge machine's IP manually. - Send Port: Must match
osc_listen_portin the bridge config (default 9000) - Receive Port: Must match
osc_send_portin the bridge config (default 8000) - Make sure the connection is enabled
If your layout uses a specific connection number (e.g. Connection 1), make sure the OSC messages in your layout are configured to send/receive on that same connection.
- Shift + right-click
osc-obs-bridge.exeand select Create shortcut - Press
Win+R, typeshell:startup, and press Enter β this opens your Startup folder - Move the shortcut into that folder
The bridge will now start automatically when you log in.
- Right-click
osc-obs-bridge.exeand select π Pin to Start
The tray dot shows connection status at a glance:
| Icon | Meaning |
|---|---|
| π’ | Connected to OBS |
| βͺ | Starting up, or waiting for OBS (auto-reconnects every 5s) |
| π΄ | Error β right-click to see details (e.g. password not set, password incorrect) |
Right-click menu:
- Status line β current state and active scene name
- Open Config β opens
config.jsonin your text editor - Reload Config β applies config changes without restarting
- Open Log File β opens the log for debugging
- Quit β exits the bridge
| Setting | What to set it to |
|---|---|
obs_host |
IP of the machine running OBS. Leave as 127.0.0.1 if OBS runs on the same machine as the bridge |
obs_port |
Must match the port in OBS > Tools > WebSocket Server Settings (default 4455) |
obs_password |
Must change. Copy from OBS > Tools > WebSocket Server Settings |
osc_listen_host |
Default "auto" β detects local IP. Set manually if you have multiple network interfaces |
osc_listen_port |
Must match TouchOSC's send port (default 9000) |
osc_send_host |
Default "broadcast" β auto-derives from osc_listen_host. Or set a specific tablet's IP |
osc_send_port |
Must match TouchOSC's receive port (default 8000) |
log_file |
Where to write logs (default osc-obs-bridge.log next to the exe) |
- Right-click the tray dot to see the error message in the status line
- "password not set" β set
obs_passwordin config.json, then Reload Config - "password incorrect" β check the password matches OBS > Tools > WebSocket Server Settings exactly (case-sensitive)
- Is OBS running with the WebSocket server enabled? (Tools > WebSocket Server Settings)
- If OBS is on a different machine, check that
obs_hostis set to that machine's IP and its firewall allows TCP on the WebSocket port
- Windows Firewall may be blocking it. On first run, Windows asks to allow network access β if you clicked Cancel or Block, the bridge will be silently blocked. To fix:
- Open Windows Defender Firewall with Advanced Security (search for it in the Start menu)
- Click Inbound Rules on the left
- Find any
osc-obs-bridge.exerules with Block in the Action column - Right-click and Delete those Block rules
- Restart the bridge β it will prompt again, click Allow
- Check that TouchOSC's send port matches
osc_listen_portin the bridge config
- Is
osc_send_hostset to"broadcast"or your tablet's IP? (not127.0.0.1) - Do
osc_listen_portandosc_send_portmatch the ports in your TouchOSC connection settings? (note: TouchOSC's "send port" is the bridge's "listen port" and vice versa) - Are the tablet and bridge machine on the same network?
- The bridge advertises itself via mDNS/Zeroconf. This may take a few seconds to appear.
- Make sure the bridge is running and the tray dot is visible
- If it still doesn't appear, enter the bridge IP and port manually in TouchOSC
- The bridge auto-detects scene changes via OBS events and polls every 1 second for reordering. If it's not updating, check the log file for errors
- Use Reload Config from the tray menu β editing the file alone doesn't apply changes
- Check the log file for config parse errors (missing comma, trailing comma, etc.)
This section is for anyone building or modifying a TouchOSC layout (or any OSC controller) to work with this bridge.
These are OSC messages the bridge listens for:
Request the list of all scenes in OBS.
- Arguments: none
- Response:
/sceneListReturn(see below)
Request which scene is currently active.
- Arguments: none
- Response:
/activeSceneReturn(see below)
Switch to a scene.
- Arguments: scene name (string) OR scene index (integer, 1-based)
- Response: The bridge sends
/activeSceneReturnautomatically via the scene change event - On error: If the scene name doesn't exist or the index is out of range, the bridge sends back
/sceneListReturnwith the current list so the controller can resync
Examples:
/scene "Band Logo" -- switch by name
/scene 3 -- switch to 3rd scene (1-based)
These are OSC messages the bridge sends back:
The full list of scene names.
- Arguments: string, string, string, ... (one per scene, in OBS order)
- Sent in response to:
/sceneList, or automatically when scenes are added/removed/renamed/reordered in OBS
Example:
/sceneListReturn "Band Logo" "Intermission" "Camera 1" "Camera 2"
The currently active scene.
- Arguments: index (int, 0-based), name (string)
- Sent in response to:
/activeScene, or automatically whenever the active scene changes in OBS (from any source β TouchOSC, OBS itself, hotkeys, etc.)
Example:
/activeSceneReturn 2 "Camera 1"
The bridge proactively pushes updates without being asked:
| OBS Event | What's Pushed |
|---|---|
| Active scene changes | /activeSceneReturn |
| Scene created | /sceneListReturn |
| Scene removed | /sceneListReturn |
| Scene renamed | /sceneListReturn |
| Scene list reordered | /sceneListReturn (detected by 1s polling) |
This keeps all connected controllers in sync even when changes happen directly in OBS.
A typical TouchOSC Lua script for a radio button scene switcher:
function init()
sendOSC("/sceneList")
end
function onReceiveOSC(message, connections)
local path = message[1]
if path == "/sceneListReturn" then
-- message[2] is an array of {value = "scene name"} tables
-- Update your radio button steps and labels here
sendOSC("/activeScene")
elseif path == "/activeSceneReturn" then
-- message[2][1].value is the 0-based index
-- Set your radio button value here
end
end
function onValueChanged(key)
if key == "x" then
local sceneName = scenesList[self.values["x"] + 1]
sendOSC("/scene", sceneName)
end
endThe Linux build runs the same tray app via GTK. It needs a Rust toolchain plus a few system libraries.
Install the system dependencies (Debian/Ubuntu, including Kubuntu 26.04):
sudo apt-get update
sudo apt-get install -y build-essential pkg-config libgtk-3-dev libxdo-dev libayatana-appindicator3-dev(On distros without the Ayatana package, use libappindicator3-dev instead.)
Install Rust if you don't have it (https://rustup.rs), then build:
cargo build --release # produces target/release/osc-obs-bridgeRun it from a graphical session β the tray icon requires a display (X11 or Wayland) and a system tray that supports the StatusNotifier/AppIndicator protocol. On KDE Plasma this works out of the box. On GNOME you may need the AppIndicator extension.
See CLAUDE.md for architecture, build instructions, and developer documentation.