A lightweight Windows tray app that detects Steam achievement unlocks in real time and pushes them to your StreamTrackr account — overlay, Twitch chat, Discord, stats, all updated within a second of the unlock instead of waiting on Valve's Web API cache.
End-to-end latency from achievement unlock to your stream overlay: under one second.
- Watches the currently-running Steam game by reading Steam's own local
cache files (
<Steam>\appcache\stats\UserGameStats_*.bin). - On a new unlock, posts the event to the StreamTrackr backend over HTTPS, which fans it out to your overlay (SSE), Twitch chat, Discord webhooks, session stats and goals.
- Runs quietly in the Windows tray with a status icon that reflects whether your achievements are actually being delivered — green when the last push was accepted, amber when StreamTrackr has nowhere to put it (no overlay open, tracker on another platform or another game), red when nothing can arrive at all (signed out, subscription inactive, or no reply from the API for several minutes).
- Auto-updates itself in the background — new versions are downloaded, SHA-256-verified, and applied on the next restart.
Yes — by architecture, not just by policy.
The companion never:
- Loads
steam_api.dll/steam_api64.dllor any other Steam DLL - Calls
SteamAPI_Init,SetAchievement, or any Steamworks function - Opens a process handle on Steam or any game
- Reads or writes game process memory
- Injects code, hooks, or overlays into anything
- Bundles or ships any Valve binary
What it actually does, technically:
- Reads
HKCU\Software\Valve\Steam\RunningAppID(a Windows registryDWORD) every 5 seconds to know which game is active. - Reads two files Steam writes for its own UI:
<Steam>\appcache\stats\UserGameStatsSchema_<appid>.bin— the list of achievements + their bit positions<Steam>\appcache\stats\UserGameStats_<sid>_<appid>.bin— your current unlock state
- POSTs
{ appId, achievement: { apiName } }toapi.streamtrackr.comover HTTPS when it sees a new bit flip from 0 to 1.
That's the whole loop. Every file it touches is a regular file owned by your Windows user account, in your own user-writable directory. There is no scenario where any of this is visible to a kernel-level anti-cheat — the companion is just a userspace process reading config files, the same way Steam itself, a backup tool, or File Explorer would.
For comparison: Steam Achievement Notifier,
which is sold on the Steam Store, does call SteamAPI_Init against
the running game to read achievements. This companion takes the
stricter route and avoids the SDK entirely — strictly less invasive
than a product Valve has approved on their own storefront.
- Windows 10 or 11 (64-bit)
- Steam installed and logged in to the account you stream from
- A StreamTrackr Pro account (the companion is a Pro feature)
Grab the latest installer from the releases page:
streamtrackr-companion-setup.exe
Run it. The installer drops the app into %LocalAppData%\Programs\StreamTrackr Companion
(no admin prompt) and offers to launch at Windows startup. On first
launch, a browser tab opens to pair the companion with your StreamTrackr
account.
About the SmartScreen warning: until this release is code-signed, Windows may show a "Windows protected your PC" prompt on first run. Click More info → Run anyway to continue. The warning fades on its own as more users install the same binary.
Once paired and running, you don't have anything to do — the app sits in the tray and works while you play.
Right-click the tray icon for status info, sign-out, manual update check, and "Open dashboard" / "Quit".
The companion is written in Go (cgo is only needed for the system tray on Windows). The build pipeline produces a single Windows binary plus an NSIS installer.
- Cross-compiling from macOS/Linux:
brew install mingw-w64 makensis(or the equivalent on your distro) - Native on Windows: install Go 1.26+ and NSIS. CGO needs a working MinGW or MSVC toolchain — TDM-GCC is the easiest on Windows.
# Build the .exe only
make build
# Build the .exe + NSIS installer
make installer VERSION=0.1.0
# macOS sanity build (no tray, no installer — just verifies the code compiles)
make mac
# Clean build artefacts
make cleanThe VERSION is baked into the binary via -ldflags and surfaced in
the tray menu. Without it, the build is tagged dev and skips the
auto-update polling.
Steam keeps a per-user binary cache of achievement state on disk:
<Steam>\appcache\stats\UserGameStatsSchema_<appid>.bin
<Steam>\appcache\stats\UserGameStats_<steamid3>_<appid>.bin
Both are in Valve's BinaryKV format. The schema enumerates achievements
as (statID, bit, apiName) triplets; the user stats file holds the
current int32 Value of each stat. An achievement is unlocked iff its
bit is set in the matching stat's value.
The companion polls the stats file's mtime 4× per second. Steam
rewrites the whole file every time a game calls StoreStats — which
happens immediately when an achievement notification pops in-game. When
the mtime advances, we re-parse, diff against the last snapshot, and
emit each newly-unlocked achievement as an HTTP push.
End result: same sub-second latency the SDK-based design used to give us, with zero SDK dependency, zero bundled DLL, zero process touched — purely reading files that the OS already grants you read access to as your own user.
.
├── main.go Entry point (subcommand dispatch + watcher loop)
├── tray_*.go Tray UI: status rows, menu, refresh ticker
├── tray_icon_status.go Status badge overlay generated at startup
├── update_dialog_windows.go Interactive update flow with native dialogs
├── login.go OAuth-style loopback callback flow
├── pusher.go HTTP push → /api/companion/steam/unlock
├── updater.go Auto-update: manifest fetch + SHA-256 + apply
├── token_store.go Token persisted at %AppData%\StreamTrackr
├── autostart_windows.go HKCU\Run registry toggle
├── welcome_windows.go First-launch native MessageBox
├── dialog_windows.go Reusable MessageBox helpers
├── kv_binary.go Valve BinaryKV (binary VDF) parser
├── steam_user.go Active steamID3: registry → loginusers.vdf → userdata
├── stats_reader.go Schema + user-stats cache reader + bitmask math
├── app_state.go Shared state: transport / delivery / capture
├── health.go Dot colour + watchdog + goroutine supervisor
├── assets/icon.ico Tray + window icon (multi-res 16/32/48)
├── installer/installer.nsi NSIS Modern UI installer (per-user, no UAC)
└── .github/workflows/ CI: builds + publishes a release on tag push
Run streamtrackr-companion --dump-stats <appid> from a terminal on any
machine with Steam installed to dump the currently-parsed schema +
achievement state for a given app. Output looks like:
steam-path : C:\Program Files (x86)\Steam
steamID3 : 138499704 (steamID64 76561198098765432)
appid : 346900
schema : C:\Program Files (x86)\Steam\appcache\stats\UserGameStatsSchema_346900.bin
stats : C:\Program Files (x86)\Steam\appcache\stats\UserGameStats_138499704_346900.bin
🏆 stat=1 bit=0 ACH_FIRST_KILL
stat=1 bit=1 ACH_HEADSHOT
🏆 stat=1 bit=2 ACH_VETERAN
...
Total: 12/47 unlocked
If anything mismatches what Steam's own UI shows, file an issue — that's the regression surface we care about most.
The log lives at %AppData%\StreamTrackr\companion.log (rotated at
5 MiB, one backup). Every API interaction is one greppable line, so
"is this companion actually sending anything?" is answerable from the
log alone:
grep ' unlock ' # every push, with the API's verdict
grep 'current-game' # the once-a-minute heartbeat
grep 'health:' # every green/amber/red transition
unlock appid=346900 api="ACH_VETERAN" attempt=1/3 http=200 status=injected reason=- tracker=abc → green
unlock appid=346900 api="ACH_VETERAN" attempt=1/3 http=200 status=no_tracker reason=other_platform tracker=- → amber
unlock appid=346900 api="ACH_VETERAN" attempt=1/3 http=403 code=PRO_LICENSE_EXPIRED msg="your Pro subscription has expired"
current-game http=200 appid=346900
current-game skipped=no-token
health: green → red — your Pro subscription has expired
status=- or reason=- means the server didn't send that field; the
companion treats it as "unknown", never as an error.
- All requests to the backend use a long-lived bearer token persisted
on disk at
%AppData%\StreamTrackr\token.json(mode 0600). The token is SHA-256 hashed at rest on the server side. - The pairing flow uses an OAuth-style auth code with a 5-minute TTL,
bound to a single-use 32-hex
stateparameter, and only accepts loopback redirect URIs (http://127.0.0.1:<port>/cb). - The companion never loads any native code at runtime: no Steamworks DLL, no SDK initialisation, no hook into any Steam process.
- The auto-updater is restricted to two GitHub-controlled hostnames
(
github.com,objects.githubusercontent.com) over HTTPS, and every downloaded binary is SHA-256-verified against a manifest before being applied.
MIT — see the LICENSE file for the full text.
- StreamTrackr — the parent product (OBS overlay + Twitch / Discord integrations + stats / goals)
- Steam Achievement Notifier — uses the same Steamworks SDK pattern, available on Steam