Network Limiter
Per-process network bandwidth limiter for Windows. Throttle the download
and upload speed of individual applications (by PID) in real time, built on
WinDivert (pydivert) and psutil.
Ships as two things:
- A library (
network_limiter) — a clean, GUI-free API you can drive from your own Python code. - A desktop GUI (optional
[gui]extra) — a live per-process traffic table with toolbar, status bar, and inline limit editing.
⚠️ Windows only. WinDivert is a Windows kernel driver and requires Administrator privileges.
Features
- Throttle download and/or upload speed per process (KB/s).
- Live per-application throughput monitoring.
- Works with TCP and UDP, including QUIC / HTTP3 (wildcard-bound UDP fallback).
- Use it as a library (no GUI dependency) or as a desktop app.
- Modern dark-themed GUI: toolbar, search, status bar with admin indicator, and double-click inline limit editing.
Requirements
- Windows 10 / 11
- Python 3.10+
- Administrator privileges (WinDivert)
Installation
As a library (no GUI)
pip install network-limiter
With the desktop GUI
pip install "network-limiter[gui]"
From source
git clone https://github.com/EmperorHeyman/network-limiter.git
cd network-limiter
pip install ".[gui]" # or: pip install . (library only)
Library usage
The core engine is NetworkLimiter. It runs its capture/throttle loop on a
background thread, so you start it, set limits, and stop it whenever you like.
from network_limiter import NetworkLimiter, find_pids_by_name, list_processes
# 1. List running processes
for proc in list_processes()[:5]:
print(proc["pid"], proc["name"])
# 2. Start the engine (needs Administrator)
limiter = NetworkLimiter()
limiter.start()
# 3. Limit every Chrome process to 500 KB/s down, 100 KB/s up
for pid in find_pids_by_name("chrome.exe"):
limiter.set_limit(pid, down_kbs=500, up_kbs=100)
# 4. Inspect current limits
print(limiter.get_limits())
# 5. Remove limits and stop
limiter.clear_limit() # clear all (or pass a pid to clear one)
limiter.stop()
Context manager
from network_limiter import NetworkLimiter
with NetworkLimiter() as limiter:
limiter.set_limit(1234, down_kbs=1000) # 0 = unlimited for that direction
input("Throttling PID 1234... press Enter to stop")
# engine stops automatically on exit
Live stats via callbacks
Callbacks fire on the engine's background thread (marshal to your UI thread if needed):
from network_limiter import NetworkLimiter
def on_stats(rows):
for row in rows[:3]:
print(f"{row['name']:<25} ↓{row['down_kbs']:.1f} ↑{row['up_kbs']:.1f} KB/s")
limiter = NetworkLimiter(
on_stats=on_stats,
on_status=print,
on_error=lambda msg: print("ERROR:", msg),
)
limiter.start()
API summary
| Member | Description |
|---|---|
NetworkLimiter(packet_filter, on_stats, on_status, on_error, on_limits_changed) |
Create an engine. |
.start() / .stop(timeout=5.0) |
Start / stop the background loop. |
.set_limit(pid, down_kbs=0, up_kbs=0, name=None) |
Throttle a PID (0 = unlimited). |
.clear_limit(pid=None) |
Remove one limit, or all when pid is None. |
.get_limits() / .get_stats() |
Current limits / latest throughput. |
.running |
Whether the loop is alive. |
list_processes() |
[{"pid", "name"}, ...] snapshot. |
find_pids_by_name(name) |
PIDs whose name matches (substring, case-insensitive). |
GUI usage
After installing with the [gui] extra:
network-limiter
or
python -m network_limiter
The app relaunches itself elevated via UAC. Double-click a Limit ↓ or
Limit ↑ cell to throttle that app inline, use the toolbar to clear limits,
and the search box to filter. The status bar shows the monitor state and
whether you are running as Administrator.
Build a standalone .exe
A PyInstaller spec is included. It bundles the
WinDivert driver and requests elevation (uac_admin).
pip install ".[dev]"
pyinstaller network_limiter.spec
# -> dist/network_limiter.exe
How it works
WinDivert intercepts packets in the kernel and hands them to user space.
network_limiter maps each packet to a PID via psutil connection tables
(with a port-only fallback for wildcard-bound UDP sockets used by QUIC/HTTP3),
then delays packets for throttled PIDs using a sliding-window rate calculation
before re-injecting them. Unthrottled traffic passes straight through.
License
MIT © 2026 Lukáš Peterek
Metadata
Release files for network-limiter 1.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| network_limiter-1.0.1.tar.gz | 14.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| network_limiter-1.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 29.3 kB
Release files / network_limiter-1.0.1.tar.gz
| Download URL | network_limiter-1.0.1.tar.gz |
|---|---|
| Size | 14.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
65b47e00ff73c47b03de386e8706cfeb37cd095f3ab7b52672918c0e99da64ce
|
|
BLAKE2b-256 checksum How to use checksums |
7544caa84a758586e703a3233de8a0311531ced7ec442dfd526880c4e0167352
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.3
|
Release files / network_limiter-1.0.1-py3-none-any.whl
| Download URL | network_limiter-1.0.1-py3-none-any.whl |
|---|---|
| Size | 15.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ff5fa71a1ea5b137d9bd356043181cc582e2098e51501a173d466ed626048a05
|
|
BLAKE2b-256 checksum How to use checksums |
e87134d37180cf12d4524628124df6d65f239cc90f28c16436f6567945866c52
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.3
|