goxlr-streamlabs-sync
Control your separated Streamlabs audio tracks with your GoXLR's physical faders.
🇫🇷 Version française
The GoXLR only exposes ONE mixed capture device to Windows (Broadcast Stream Mix), so your stream/recording gets everything baked together - impossible to edit voice, game and music separately afterwards. The well-known workaround is to capture each GoXLR playback device (Game, Music, Chat, System) as its own Audio Output Capture source in Streamlabs Desktop and record them on separate tracks. But those captures are taken before the GoXLR hardware mixing, so your faders and mute buttons stop having any effect on them.
This tool fixes that: it listens to the GoXLR Utility websocket API and mirrors every fader move and mute press onto your Streamlabs Desktop audio sources in real time, through Streamlabs' JSON-RPC API.
GoXLR hardware ──USB──> GoXLR Utility daemon ──websocket──> goxlr-streamlabs-sync ──JSON-RPC──> Streamlabs Desktop
Similar tools exist for OBS Studio (goxlr-obs-fader-sync, obs-goxlr-fader-sync-plugin) - this one is for Streamlabs Desktop.
Features
- Real-time volume sync: GoXLR fader (0-255) → Streamlabs source volume slider
- Mute sync with stream-aware logic: only mutes the source when the GoXLR mute actually affects the stream (configurable)
- Any GoXLR channel can be mapped to any number of Streamlabs sources
- Works with the GoXLR Full and GoXLR Mini, and with multiple devices
- Zero npm dependencies, single small Node.js process, auto-reconnects to both ends
- Local web dashboard (live volumes, mute states, logs) and a system tray icon - nothing cluttering your taskbar
- Configure everything from the dashboard: mappings editor (suggesting your live Streamlabs sources), mute behavior, Start with Windows toggle - applied instantly, no restart
- Standalone
.exe available (no Node.js install needed), built transparently by GitHub Actions
- Update notifications (checks the GitHub releases once a day, can be disabled)
--list mode to discover your channels and exact source names
--dry-run mode to test safely
Requirements
- Windows with Node.js 22+
- GoXLR Utility running (the unofficial replacement for the official GoXLR App)
- Streamlabs Desktop
Installation
Option A - standalone executable (easiest)
Download goxlr-streamlabs-sync.exe from the Releases page, put it in its own folder, and run it. On first run it creates a config.json next to the exe - edit the mappings, run it again, done. No Node.js required.
> About Windows SmartScreen: the exe is not code-signed (certificates cost money for a free community tool), so the first launch may show "Windows protected your PC" → click More info → Run anyway. Every release is built transparently from this repository's source by GitHub Actions, and the SHA256 checksum is published next to it (SHA256SUMS.txt). If in doubt, audit the code and build it yourself (Option C) - you'll get a byte-identical behavior.
Option B - run from source
git clone https://github.com/Corail44/goxlr-streamlabs-sync.git
cd goxlr-streamlabs-sync
Requires Node.js 22+. There is nothing to build and no npm install needed.
Option C - build the exe yourself
npm install
npm run build:exe -> build/goxlr-streamlabs-sync.exe
Setup
1. Create the separated capture sources in Streamlabs
For each GoXLR sub-device you want as its own track, add a source in Streamlabs Desktop:
| Streamlabs source (suggested name) | Source type | Windows device |
|---|
Mic (GoXLR) | Audio Input Capture | Chat Mic (TC-Helicon GoXLR) |
Game (GoXLR) | Audio Output Capture | Game (TC-Helicon GoXLR) |
Music (GoXLR) | Audio Output Capture | Music (TC-Helicon GoXLR) |
Chat (GoXLR) | Audio Output Capture | Chat (TC-Helicon GoXLR) |
System (GoXLR) | Audio Output Capture | System (TC-Helicon GoXLR) |
Then in Settings → Output (Advanced mode) → Recording: set the format to MKV or MP4 and enable up to 6 audio tracks. In the advanced audio settings (cog in the Mixer panel), assign each source to its own track. Keep your Broadcast Stream Mix capture on track 1 only (that's what goes live), and put the separated sources on tracks 2-6 (recording only). Set audio to 48 kHz to match the GoXLR.
2. Configure the sync
The easy way: open the dashboard (http://127.0.0.1:14571), click Settings, then map each GoXLR channel to a Streamlabs source (the field suggests your live sources), pick the mute behavior, optionally enable Start with Windows and paste your Streamlabs API token, then Save. Changes apply instantly, no restart needed.
The file way: edit config.json (start from config.example.json):
{
"sync": {
"mappings": [
{ "channel": "Mic", "source": "Mic (GoXLR)" },
{ "channel": "Music", "source": "Music (GoXLR)" },
{ "channel": "Game", "source": "Game (GoXLR)" }
]
}
}
Valid channels: Mic, LineIn, Console, System, Game, Chat, Sample, Music, Headphones, MicMonitor, LineOut. Run node src/index.js --list to print your GoXLR channels and every Streamlabs source name.
Where is config.json? Search order: --config → config.json in the current folder → next to the exe / project root → %APPDATA%\goxlr-streamlabs-sync\config.json. The packaged exe creates the APPDATA one on first run, so your settings persist no matter where the exe is launched from.
3. Run it
A tray icon appears in the notification area: right-click for Open dashboard / Quit, double-click to open the dashboard.
- Standalone exe: just run
goxlr-streamlabs-sync.exe - it goes straight to the background (tray icon, no console window). Use --console to keep it attached to a terminal and see the logs.
- From source, no window: double-click
start-hidden.vbs.
- From source, with console:
start.bat or npm start.
Launching it again while it's already running simply reopens the dashboard (single instance). Stop it from the tray icon, the dashboard's Quit button, or stop.bat.
Move a fader on the GoXLR - the matching Streamlabs volume slider follows. 🎚️
To launch it automatically with Windows: enable Start with Windows in the dashboard settings (it registers the proper command in HKCU\...\Run).
The dashboard
The tool serves a small local web page (no external service, no dependency): connection status of both ends, live channel volumes, mute states, mapped sources and recent logs - plus a Quit button. Default address: http://127.0.0.1:14571. Set ui.host to "0.0.0.0" if you want to open it from another device on your network. Closing the tab never stops the sync.
The interface language follows your browser (French/English) and can be forced with the language selector in the header; the choice is remembered per browser. Adding a language is a small PR: one dictionary block in src/ui.html.
Connecting to Streamlabs: pipe vs websocket
By default ("transport": "auto"), the tool connects through Streamlabs' local named pipe (\\.\pipe\slobs) - zero configuration needed.
Known Streamlabs quirk: the pipe listener is single-use. If a client disconnects (e.g. you stop this tool), Streamlabs does not recreate the pipe until it restarts. So if you restart the sync while Streamlabs stays open, the pipe will be unavailable. Two options:
- restart Streamlabs Desktop, or
- set a token so the tool can fall back to the websocket: in Streamlabs go to Settings, Remote Control, enable Allow third-party connections, then copy the API token shown there. Paste it in the dashboard settings (a Test button validates it live); the websocket host and port are editable there too, in case you changed the port in Streamlabs.
With a token configured, auto tries the pipe first and falls back to the websocket seamlessly.
Configuration reference
| Key | Default | Description |
|---|
goxlr.url | ws://127.0.0.1:14564/api/websocket | GoXLR Utility websocket |
goxlr.serial | null | Pin a specific device (serial) if you own several; null = first found |
streamlabs.transport | auto | auto, pipe or websocket |
streamlabs.pipeName | slobs | Named pipe name |
streamlabs.url | ws://127.0.0.1:59650/api | Streamlabs SockJS endpoint (websocket transport) |
streamlabs.token | null | API token (Settings → Remote Control), required for websocket |
sync.throttleMs | 50 | Min delay between two volume updates per source (fader sweeps) |
sync.curveExponent | 1.0 | deflection = (volume/255)^exponent. 1.0 = slider mirrors fader position |
sync.muteMode | follow_stream | See below |
sync.syncOnConnect | true | Push the full GoXLR state to Streamlabs on (re)connect |
sync.mappings[] | - | { channel, source, syncVolume?, syncMute? } |
ui.enabled | true | Serve the local web dashboard |
ui.host | 127.0.0.1 | Dashboard bind address (0.0.0.0 to allow LAN access) |
ui.port | 14571 | Dashboard port (also used as the single-instance lock) |
ui.openBrowser | false | Open the dashboard on startup (the --open flag does the same) |
ui.tray | true | Show the system tray icon (Windows) |
updateCheck | true | Check GitHub once a day for a newer release (shows a dashboard banner) |
Mute modes
The GoXLR mute button can target different outputs (mute to All / Stream / Voice Chat / Phones / Line Out - and hold always mutes everywhere).
follow_stream (default): the Streamlabs source is muted only when the GoXLR mute affects the stream mix (MutedToAll, or MutedToX with target All/ToStream). A "mute to headphones" press won't mute your recording - which is usually what you want.
any: any mute state on the channel mutes the source.
off: never touch mutes.
The mic cough button is handled too (counts as a mute on the Mic channel).
Limitations
- One-way sync (GoXLR → Streamlabs). Moving a slider in Streamlabs does not move the motorized fader.
- GoXLR submixes are not supported yet - the main channel volume is used.
- Channels not assigned to a fader can still sync volume (changed via the Utility UI), but have no mute button to sync.
Troubleshooting
GoXLR Utility unreachable - make sure the GoXLR Utility daemon is running (its icon sits in the system tray). The official GoXLR App must not be used at the same time.
Cannot reach Streamlabs Desktop - Streamlabs isn't running, or its named pipe is stale (see pipe vs websocket).
Sources not found in Streamlabs - the source names in config.json must match the Streamlabs source names exactly (case-sensitive). Run node src/index.js --list.
- Run with
--verbose to see every patch and API call, and --dry-run to test without touching Streamlabs.
Contributing
Issues and PRs welcome! The codebase is intentionally small and dependency-free:
src/index.js entry point & CLI
src/goxlr.js GoXLR Utility websocket client (status mirror + JSON Patch)
src/streamlabs.js Streamlabs JSON-RPC client (named pipe + SockJS websocket)
src/sync.js mapping engine (throttle, curves, mute logic)
src/config.js config loading & validation
src/jsonpatch.js minimal RFC 6902 implementation
Credits
License
MIT