- C# 98.8%
- PowerShell 1.2%
| .github/workflows | ||
| UdonMQTT-Bridge | ||
| .gitignore | ||
| build-publish.ps1 | ||
| LICENSE | ||
| README.md | ||
| UdonMQTT-Bridge.sln | ||
UdonMQTT-Bridge
UdonMQTT is a bidirectional MQTT bridge for VRChat worlds, enabling real-time communication between in-world UdonSharp behaviours and external MQTT brokers. This is the desktop release — the same bridge engine with a WPF interface instead of a console window.
Overview
Because VRChat's Udon runtime is heavily sandboxed (no sockets, no HTTP), UdonMQTT uses two OS-level channels to move data in and out of the game:
- Ingress (External → VRChat): Win32 keyboard events via
PostMessage(WM_CHAR) - Egress (VRChat → External): VRChat log file tailing (
Debug.Logas a write-only serial port)
UdonMQTT-Bridge adds:
- One-click start/stop with a live status indicator
- Live status dashboard showing connection states and message counters
- Settings editor for all configuration options (no manual JSON editing)
- Persistent console log with timestamps, auto-scroll, and log rotation
- Prometheus metrics polling for real-time observability
Requirements
- Windows 10/11
- .NET 8.0 Runtime (Desktop)
- VRChat running locally (for log parsing and keyboard events)
- An accessible MQTT broker
Getting Started
- Download the latest release and run
UdonMQTT-Bridge.exe. - Open the Settings tab and configure your MQTT broker address, port, credentials, and topics.
- Click Save, then switch to the Status tab and click Start.
- The status cards update every 2 seconds. Console output appears in the log panel below.
Configuration is stored at %LOCALAPPDATA%\UdonMQTT\mqtt_config.json and is created automatically with defaults on first run.
Features
Status Tab
The status tab shows the live state of UdonMQTT after t is started.
Connection status cards:
| Card | Description |
|---|---|
| MQTT Broker | Whether the MQTT client is connected to the broker |
| VRChat Process | Whether VRChat.exe is running |
| VRChat Window | Whether the VRChat window is in the foreground |
| Log File | Whether the VRChat log file is being actively parsed |
| Udon World | Whether the current VRChat world has loaded an Udon script |
| Active Subscriptions | Number of active MQTT topic subscriptions |
Counter cards: Messages Published, Messages Received, Keyboard Strings Sent, Log Lines Parsed, Errors, Dropped Messages, Reconnects, and Uptime.
Metrics are fetched from the Prometheus endpoint exposed by UdonMQTT (configurable host/port). A banner is shown when metrics are unavailable. The Refresh button forces an immediate update.
Console log: Timestamped output from UdonMQTT, capped at 500 lines. Auto-scroll can be toggled. Logs are saved to %LOCALAPPDATA%\UdonMQTT\UdonMQTT_*.log with rotation (max 5 files).
Settings Tab
All settings are edited in-app. Changes are not applied until Save is clicked. Unsaved changes are indicated in the status bar.
| Group | Settings |
|---|---|
| MQTT | Broker address, port, username, password, TLS toggle, allow untrusted certs, ignore cert errors, base topic, join-world topic, auto-start on launch |
| Rate Limiting | Max chars/sec, burst size, min newline interval (ms), chunk size (chars) |
| Timing | Log parser interval (ms), chunk send interval (ms), key rotation interval (min), key grace period (min), log search timeout (sec) |
| Messages & Monitoring | Max message size (bytes), Prometheus host, Prometheus port |
| Debug | Debug mode toggle |
Reset Defaults restores all fields to built-in defaults without saving. Reload discards unsaved edits and reloads from disk.
Security
- Connection key rotation: UdonMQTT generates a random 4-character alphanumeric key, rotated on a configurable interval with a grace period for the old key. Log commands must include the current key to be processed, preventing stale log replay.
- Topic restriction: All MQTT operations are restricted to the configured
BaseTopicprefix. Publishing or subscribing to topics outside this prefix (or under the reservedbridge/subtopic) is rejected. - User whitelist: The in-world UdonSharp behaviour only activates for players listed in
whitelistedUsers. For all other players, the GameObject is disabled entirely.
Monitoring
UdonMQTT exposes Prometheus metrics at http://127.0.0.1:9100/metrics (configurable via PrometheusMetricsHost and PrometheusMetricsPort).
Key metrics: udonmqtt_mqtt_messages_published_total, udonmqtt_mqtt_messages_received_total, udonmqtt_mqtt_connected, udonmqtt_world_connected, udonmqtt_window_found, udonmqtt_logfile_found, udonmqtt_keyboard_strings_sent_total, udonmqtt_errors_total, udonmqtt_process_uptime_seconds.
World Join Tracking
The log parser detects VRChat's [Behaviour] Joining wrld_ log lines and publishes structured world join events to JoinWorldTopic as retained MQTT messages — including world ID, instance ID, group info, region, and age gate status. No Udon involvement required.
Configuration Reference
Defaults written on first run:
| Setting | Default | Description |
|---|---|---|
BrokerAddress |
localhost |
MQTT broker hostname |
Port |
1883 |
MQTT broker port |
Username |
udonmqtt |
Broker username |
Password |
udonmqtt |
Broker password |
UseTLS |
false |
Enable TLS |
AllowUntrustedCert |
false |
Accept untrusted certificates |
IgnoreCertErrors |
false |
Ignore all certificate errors |
BaseTopic |
udonmqtt |
Topic prefix restriction |
JoinWorldTopic |
udonmqtt/bridge/joinworld |
Topic for world join events |
MaxCharsPerSecond |
400 |
Token bucket rate limit |
MinNewlineIntervalMs |
800 |
Minimum gap between message submits |
MaxBurstChars |
800 |
Token bucket burst size |
ChunkSize |
128 |
Characters per keyboard chunk |
ChunkIntervalMS |
16 |
Pause between chunks (ms) |
LogparserIntervalMS |
50 |
Log file poll interval (ms) |
KeyUpdateIntervalMinutes |
1 |
Connection key rotation interval |
KeyGracePeriodMinutes |
1 |
Old key acceptance window |
LogSearchTimeoutSeconds |
30 |
Timeout when searching for log file |
MinVrcProcessSeconds |
20 |
Minimum seconds VRChat must have been running before its log is picked up |
PrometheusMetricsHost |
127.0.0.1 |
Metrics bind address |
PrometheusMetricsPort |
9100 |
Metrics port |
MaxMessageSizeBytes |
4096 |
Maximum inbound message size |
DebugMode |
false |
Enable verbose debug output |
AutoStartOnLaunch |
false |
Start bridge automatically on app launch |
Building from Source
git clone https://github.com/eurofurence/UdonMQTT-Bridge
cd UdonMQTT-Bridge
dotnet build
Requires the .NET 8.0 SDK. The project targets net8.0-windows (WPF).
To produce a self-contained executable:
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true
Project Structure
UdonMQTT-Bridge/
├── Core/ # UdonMQTT engine (MQTT, keyboard injection, log parser, Prometheus)
├── Services/ # Bridge lifecycle, config I/O, metrics fetching, console capture
├── ViewModels/ # MVVM view models (MainViewModel, SettingsViewModel, DebugViewModel)
├── Converters/ # WPF value converters (bool → color/visibility, uptime formatting)
├── MainWindow.xaml # Two-tab UI (Status + Settings)
└── App.xaml # Application entry point and theme resources
VRChat TOS Compliance
UdonMQTT-Bridge is not a mod, not a cheat, and does not modify VRChat in any way.
VRChat's Community Guidelines prohibit reverse engineering and modifying VRChat applications, including code injection, sideloading, exploiting, and circumventing anti-tamper software. The TOS (Section 13) further prohibits decompiling, reverse engineering, or making modifications to any portion of the Platform.
UdonMQTT-Bridge adheres to all of these rules. It follows the same approach used by other well-established, community-accepted VRChat companion tools — such as ToNSaveManager, VRCX, VRCLogParser, and others — which read VRChat's output log files as their primary data source.
What UdonMQTT Does — And Does Not Do
No client modification. UdonMQTT is a standalone external .NET application that runs alongside VRChat as a separate process. It does not modify, patch, inject into, or interact with VRChat's process memory. It does not use DLL injection, function hooking, or any technique that alters VRChat's executable or runtime behaviour.
Log file reading (egress). Like ToNSaveManager, VRCX, and other companion tools, UdonMQTT reads VRChat's output_log_*.txt files from %AppData%Low\VRChat\VRChat\. These are plain text files that Unity writes as part of its standard logging pipeline. UdonMQTT opens them read-only with FileShare.ReadWrite, never locking or interfering with VRChat's ability to write to them. Debug.Log() is a standard Unity method that VRChat's own Udon debugging documentation encourages world creators to use.
Keyboard input (ingress). UdonMQTT uses PostMessage(WM_CHAR), a standard Windows API, to send characters to VRChat's window — functionally identical to a user typing on their keyboard. On the receiving side, Input.inputString is explicitly listed as an available API in VRChat's official Udon Input Events documentation.
No network interception. UdonMQTT does not inspect, intercept, modify, or decrypt any VRChat network traffic. Its MQTT communication is entirely separate — connecting to a user-configured broker with no relationship to VRChat's infrastructure.
| Concern | UdonMQTT's Approach |
|---|---|
| Client modification | No — standalone external process, VRChat binary untouched |
| Code injection | No — no DLL injection, hooking, or memory access |
| Reverse engineering | No — no decompilation or inspection of VRChat code |
| Anti-cheat circumvention | No — does not interact with EAC or any anti-tamper system |
| Log file reading | Read-only, same approach as ToNSaveManager / VRCX / other community tools |
| Input method | Input.inputString — officially documented Udon API |
| Output method | Debug.Log() — officially documented for Udon debugging |
| Network interception | No — MQTT traffic is entirely separate from VRChat's servers |
⚠️ Important — Do not use UdonMQTT to collect user data against users' will. UdonMQTT is a transport layer. World creators building on top of it are responsible for what data they publish via MQTT. VRChat's SDK License prohibits content from sending data collected from users to external servers without authorization, and Section 8.10 of the TOS prohibits worlds from collecting information that provides the real identity of users. Do not use Udon APIs (such as
VRCPlayerApi) to harvest other players' display names, positions, or other personal information and publish it to MQTT without those players' informed consent.
Note: This section reflects our understanding of VRChat's Terms of Service and Community Guidelines as of March 2026. TOS interpretation is ultimately at VRChat's discretion.
License
See LICENSE for details.