/projects/steam_throttle
TL;DR: I was sick of Steam updates and downloads causing lag during League games. I mostly play Arena, so I built a small Windows app that lets Steam keep downloading, but automatically throttles it while I am fighting. It restores full speed when it is safe and puts Steam back the way it found it when automation stops.
I have fast internet. That somehow makes this problem more annoying, not less.
Steam is perfectly happy to consume every bit of bandwidth it can find. Most of the time, that is exactly what I want. Then a League match starts, Steam discovers a 40 GB update, and suddenly my ping is doing its own ranked climb.
The obvious answer is to pause the download. I tried that. Apart from wasting perfectly good bandwidth between fights, pausing could sometimes make a download lose progress or restart work it had already done. I did not want another reminder or a button I had to remember to press. I wanted Steam to keep downloading—just politely.
So I created Steam Throttle.
Built Around Arena
I mostly play Arena, where a match naturally alternates between short fights and downtime. That makes a fixed "game open, downloads off" rule unnecessarily blunt.
The behavior I wanted was simple:
| League state | Steam behavior |
|---|---|
| Outside a match | Full speed |
| Loading or uncertain state | Throttled |
| Arena fight while I am alive | Throttled |
| Arena fight after I die | Full speed |
| Detectable downtime between rounds | Full speed |
| Other League modes | Throttled by default |
The default limit is 10 MB/s, but the app has a compact drag-or-type control for changing it. The rest happens automatically in the tray.
This is deliberately a throttle, not a pause. The download continues making progress without being allowed to bully the game off the network. Pausing still exists as an explicit option for non-Arena matches, but Steam Throttle will never quietly decide to pause on its own.
The Buy-Round Problem
There is one important limitation: League does not expose a dependable "the buy round has started" flag through the local data I can read.
Steam Throttle can see the Arena game mode, each player's team, and whether players are alive. It uses that to infer when combat is happening. If both teams have living players, the safe assumption is that a fight is active.
During a buy round, both teams are alive too. From the data's point of view, shopping and fighting can look identical. That means Steam Throttle will remain throttled during those buy rounds.
I would rather leave a few extra seconds of bandwidth on the table than unleash a full-speed Steam download because the app guessed wrong. Clear downtime—such as the period after a team has been eliminated—can still return to full speed. The ambiguous moments stay limited.
It is not magical detection. It is a conservative inference based on the information Riot actually makes available.
How It Works
The app combines two local League data sources. The League Client API reports broad gameflow states such as champion select, loading, and in-game. Once a match is running, Riot's Live Client Data API exposes the game mode and live player state.
Arena identifies itself as CHERRY on map 30. Steam Throttle groups the living players by team, tracks my own death and revival, and evaluates that snapshot against a small rules engine. When the desired state changes, it sends Steam one of its own runtime console commands:
+set_download_throttle <Kbps> false
+get_download_throttle
+app_download_enable <0|1>
There is no packet filtering, process injection, memory reading, firewall rule, administrator service, or cloud account. It talks to local APIs and asks the already-running Steam client to change its own setting.
The backend is written in Rust, the desktop shell uses Tauri, and the interface is Svelte. It is intentionally small, Windows-only, and happy living in the system tray.
Making It Behave Like a Desktop App
The automation was only half of the work. A utility like this needs to be quiet and predictable.
Settings save automatically without a Save button or a stream of notifications. Dragging the bandwidth value updates the interface immediately but only writes the setting when the drag ends. Closing the window minimizes it to the tray so monitoring continues. Disabling automation or exiting restores the Steam limit captured when the app started.
That last part matters. A tool should not leave somebody else's settings rearranged just because it was running for an afternoon.
I also had to serialize the Steam transitions. Game state can change quickly—death, revival, the end of a round—and an older command must never arrive after a newer decision. Before applying a transition, the app checks that the action is still wanted. That prevents a stale pause or limit from winning a race against the current state.
Download It
Steam Throttle is open source under the MIT licence. There is a per-user installer and a standalone portable build; neither requires administrator access. Windows may show a SmartScreen warning because the binaries are not Authenticode-signed.
Download
Grab the installer or portable ZIP from the latest GitHub release.
Source
Read the code, report an issue, or build it yourself.
This started as a very specific irritation: I wanted Steam to finish its downloads without ruining an Arena game. That is still the entire point. Keep the download moving, keep the ping stable, and stay out of the way.
<terminate_session />