Skip to content

netshape --docs

Complete Documentation

NetShape is a local throttling proxy for simulating degraded network conditions. It wraps any app or command, injecting latency, bandwidth limits, packet loss, and jitter so you can test how your software behaves on slow, flaky, or unreliable connections.

How It Works

NetShape starts a local HTTP/HTTPS forward proxy on your machine and launches your app as a child process. The child process inherits three environment variables:

HTTP_PROXY=http://127.0.0.1:8090
HTTPS_PROXY=http://127.0.0.1:8090
ALL_PROXY=http://127.0.0.1:8090

Any standard HTTP client that respects these variables will automatically send all traffic through the proxy. NetShape then applies the configured throttle settings — delaying packets, capping throughput, randomly dropping data — before forwarding to the real destination.

Python / LiteLLM users:

ALL_PROXY is intentionally set to an http:// URL (not socks5://). This means Python libraries like httpx, LiteLLM, and openai work without installing any extra packages (socksio is not required).

Your App  ──→  NetShape Proxy (127.0.0.1:8090)  ──→  Internet
                ↑ bandwidth cap
                ↑ latency injection
                ↑ packet loss
                ↑ jitter

A second port (8091 by default) hosts the control API and the web dashboard.

Installation

Requirements

  • • Python 3.10 or later
  • • pip

Global install (recommended for CLI use)

pip install netshape

Inside a virtual environment

python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS / Linux
source .venv/bin/activate

pip install netshape

If installed in a virtual environment, the netshape command is only available while that environment is activated. Install globally if you want it available in any terminal.

Verify the installation

netshape --version

First-Time Setup

After installing, run the interactive setup wizard once to choose your preferences:

netshape setup

The wizard presents two selection menus:

Feature selection

┌─────────────────────────────────────────────────────────────┐
│  1  Core CLI only        Terminal commands, no browser UI   │
│  2  CLI + Web Dashboard  Visual controls, live graphs, ...  │
└─────────────────────────────────────────────────────────────┘
  • Core CLI only — installs the lightest footprint. All terminal commands work fully; the dashboard URL is simply not served.
  • CLI + Web Dashboard — enables the browser UI at http://127.0.0.1:8091/dashboard whenever a session is active.

You also pick a default throttle profile. Your choices are saved to ~/.netshape/config.json. Re-run netshape setup at any time to change them.

Quick Start

# 1. (First time only) run the setup wizard
netshape setup

# 2. Run your app through a 3G profile
netshape run --profile 3g -- python app.py

# 3. In a separate terminal, check what's happening
netshape status --watch

# 4. Change conditions live (no restart needed)
netshape adjust --profile satellite

# 5. Stop the session
netshape stop

Built-in Profiles

Profiles are named presets covering common real-world network conditions.

ProfileBandwidthLatencyLossJitterDescription
2g50 kbps500 ms2%150 msTypical 2G mobile
3g780 kbps200 ms1%60 msTypical 3G mobile
4g4 Mbps80 ms0.3%25 msTypical 4G LTE
5g50 Mbps30 ms0.1%10 msFast mobile
edge240 kbps400 ms3%120 msVery slow mobile EDGE
wifi30 Mbps25 ms0.1%8 msCommon home Wi-Fi
dsl6 Mbps60 ms0.2%20 msOlder DSL broadband
cable100 Mbps20 ms0.05%5 msResidential cable
fiber1 Gbps5 ms0%2 msFast wired fiber
satellite12 Mbps650 ms0.5%80 msHigh-latency satellite
congested1.5 Mbps180 ms2.5%140 msBusy shared network
offline00 ms100%0 msAll traffic dropped

List them at any time:

netshape profiles

CLI Reference

netshape run

Starts a proxy session and launches your app as a child process. Everything after -- is the command to run.

OptionShortDescriptionDefault
--profile-pBuilt-in profile name
--bandwidth-bBandwidth limit (1mbps, 500kbps)
--latency-lAdded latency (200ms, 1s)
--lossPacket loss (2%, 0.5%)
--jitter-jLatency variance (50ms)
--timeout-tAuto-stop after duration. Units: s (seconds), m (minutes), h (hours). E.g. 30m, 1h, 90s
--portProxy traffic port8090
--log-fileWrite JSON logs to file (rotating, 10 MB)
# Use a profile
netshape run --profile 3g -- python app.py
netshape run --profile 4g -- node server.js
netshape run --profile satellite -- npx electron .

# Custom settings
netshape run --bandwidth 1mbps --latency 200ms --loss 1% -- python app.py

# Profile with one override
netshape run --profile 3g --latency 500ms -- python app.py

# Auto-stop after 30 minutes
netshape run --profile 3g --timeout 30m -- python app.py

# Save logs to file
netshape run --profile 3g --log-file proxy.log -- python app.py

netshape adjust

Applies new throttle settings to the currently running session live, with no restart needed.

OptionShortDescription
--profile-pSwitch to a built-in profile
--bandwidth-bNew bandwidth limit
--latency-lNew latency
--lossNew packet loss
--jitter-jNew jitter
# Switch profile
netshape adjust --profile satellite

# Adjust individual values
netshape adjust --bandwidth 500kbps
netshape adjust --latency 800ms
netshape adjust --loss 5%
netshape adjust --jitter 100ms

# Remove all throttling
netshape adjust --bandwidth 0 --latency 0 --loss 0 --jitter 0

netshape status

Shows the current session status.

OptionDescription
--watch, -wLive-updating table, refreshes every second
--jsonOutput raw JSON

netshape stop

Stops the active session and terminates the child process.

netshape stop

netshape test

Verifies the proxy is correctly intercepting traffic by running a local speed test.

netshape test                   # quick verification
netshape test --profile 3g      # test under 3G conditions

netshape profiles

Lists all built-in profiles with their parameters.

netshape profiles

netshape metrics

Shows detailed proxy metrics.

OptionDescription
--prometheus, -pOutput in Prometheus text exposition format

netshape rule

Manages per-endpoint throttle rules. Rules let you apply different throttle settings to specific domains or URL patterns.

# Add a rule
netshape rule add stripe\.com --bandwidth 1mbps --latency 200ms --comment "payment API"

# List rules
netshape rule list
netshape rule list --json

# Enable/disable
netshape rule enable "payment API"
netshape rule disable "payment API"

# Remove
netshape rule remove "payment API"

netshape scenario

Runs a sequence of network condition phases automatically over time.

OptionDescription
--no-waitSubmit the scenario and return immediately (useful in CI scripts)
# List scenarios
netshape scenario list

# Run a built-in scenario
netshape scenario run --builtin subway

# Start scenario without blocking the terminal
netshape scenario run --builtin subway --no-wait

# Run from a YAML file
netshape scenario run ./my-scenario.yaml

# Check status / stop
netshape scenario status
netshape scenario stop

netshape setup

Interactive first-time setup wizard. Configures which features are enabled and your default throttle profile.

netshape setup

Config file at ~/.netshape/config.json:

{
  "dashboard": true,
  "default_profile": "3g"
}

Web Dashboard

The dashboard is an optional live web UI built into the proxy. It gives full visual control over all settings.

Enabling the Dashboard

netshape setup
# → choose option 2: "CLI + Web Dashboard"

Open it at http://127.0.0.1:8091/dashboard

Dashboard Sections

  • Live Metrics — Real-time download/upload speed graphs, active throttle readings, connection status
  • Controls — Sliders for bandwidth, latency, loss, jitter; profile dropdown; apply button
  • Per-Endpoint Rules — Add, toggle, and remove domain-specific rules
  • Scenarios — Run built-in or custom scenarios; build custom ones
  • Logs — Live proxy activity log

Throttle Parameters

Bandwidth

Caps the maximum throughput in each direction using a token bucket algorithm. Short bursts above the limit are absorbed, sustained transfer is capped.

Latency

Adds a fixed delay to each packet in both directions. Key insight: Latency multiplies across round trips. At 300ms, a TLS handshake (3 RTTs) costs ~900ms before a byte of data transfers.

Loss

Randomly drops a percentage of packets. TCP will retransmit dropped packets, causing stalls. Even 5% loss with 200ms latency causes TCP retransmit storms and drastic throughput collapse.

Jitter

Varies the latency randomly ± the jitter value on each packet. Causes unpredictable response times, streaming stutter, and WebSocket lag spikes.

Per-Endpoint Rules

Per-endpoint rules let you apply different throttle settings to specific hosts or URL patterns, overriding the global session settings for matched traffic.

How Matching Works

The pattern field is a regular expression matched against the target host (for CONNECT tunnels) or the full URL (for direct HTTP). Matching is case-insensitive.

# Match exact domain
netshape rule add "stripe\.com"

# Match any subdomain
netshape rule add "\.supabase\.co"

# Match multiple services
netshape rule add "openai\.com|anthropic\.com"

Persistence

Rules are saved to ~/.netshape/rules.json automatically. When you start a new session, all saved rules are restored — in the disabled state by default.

Scenarios

Scenarios automate a sequence of network conditions over time.

Writing a Custom Scenario File

name: "Flakey Mobile Connection"
description: "Starts decent, degrades, goes offline, recovers."

phases:
  - name: "Good Start"
    duration: "30s"
    profile: "4g"
  - name: "Degrading"
    duration: "20s"
    bandwidth: "500kbps"
    latency: "300ms"
    loss: "3%"
    jitter: "80ms"
  - name: "Offline"
    duration: "10s"
    bandwidth: 0
    loss: "100%"
  - name: "Slow Recovery"
    duration: "20s"
    profile: "edge"
  - name: "Recovered"
    duration: "30s"
    profile: "3g"

Save the file to ~/.netshape/scenarios/ to make it available in the CLI and dashboard.

Built-in Scenarios

NameDescription
subwayPlatform (4G) → tunnel (dead zone) → re-emergence (2G) → platform (4G)
coffee-shop-wifiQuiet café (fast) → lunch rush (congested) → peak (packet-loss hell) → afternoon (recovering)
satelliteHigh-bandwidth but very high latency, simulating a satellite link
flight-modeNormal → airplane mode (offline) → reconnect

Compatibility Guide

What Gets Throttled

NetShape throttles HTTP and HTTPS traffic routed through the proxy. This covers the vast majority of modern app traffic.

Python Apps

All standard HTTP libraries respect HTTP_PROXY automatically — no code changes needed.

LibraryThrottled?
requestsYes
httpxYes
aiohttpYes
urllib / urllib2Yes
openai SDKYes
anthropic SDKYes
supabase-pyYes
boto3 (AWS)Yes

Node.js Apps

Library / RuntimeThrottled?Notes
axiosYes
node-fetch / fetch (Node 18+)Yes
gotYes
undiciYes
OpenAI Node SDKYes
http.get() / https.get() (native)NoRequires http-proxy-agent (HTTP) or https-proxy-agent (HTTPS) npm packages
supabase-js (Node server-side)Yes

Electron Apps

Electron has two traffic paths. The renderer process uses Chromium's network stack and ignores HTTP_PROXY — you must configure it via session.setProxy().

import { app, BrowserWindow, session } from 'electron';

async function applyProxySettings() {
  const proxyUrl = process.env.HTTP_PROXY || process.env.HTTPS_PROXY;
  if (proxyUrl) {
    const { host } = new URL(proxyUrl);
    await session.defaultSession.setProxy({ proxyRules: host });
  }
}

app.whenReady().then(async () => {
  await applyProxySettings();
  createWindow();
});

Common mistake — wrong order

// ❌ Wrong — window opens before proxy is configured
app.whenReady().then(() => {
  createWindow();           // renderer starts without proxy
  applyProxySettings();     // too late, renderer ignores this
});

// ✅ Correct — proxy configured before window opens
app.whenReady().then(async () => {
  await applyProxySettings();  // proxy first
  createWindow();
});

Do not use npm run dev (Vite dev server). Build first and launch Electron directly:

npm run build
netshape run --profile 3g -- npx electron .

Verify the proxy is intercepting renderer traffic

After launching with netshape run, open the NetShape dashboard or run netshape status --watch in another terminal. Then trigger a network request from the renderer. You should see Requests handled increment immediately.

// Quick smoke test — paste in Electron DevTools (Ctrl+Shift+I)
fetch('https://httpbin.org/get')
  .then(r => r.json())
  .then(data => {
    console.log('✓ Request succeeded — check NetShape dashboard for traffic');
    console.log(data);
  })
  .catch(err => console.error('✗ Request failed:', err));
  • • Dashboard at http://127.0.0.1:8091/dashboard → "Requests handled" should increment
  • netshape status --watch → "Connections active" should be > 0 during a request
  • • If "Requests handled" stays at 0 → applyProxySettings() is not running before createWindow()
  • • If requests fail entirely → check that session.defaultSession.setProxy() resolved before the request was made

Multi-Service Apps (Electron + Python backend)

Launch each process through its own netshape run in separate terminals.

# Terminal 1 — Electron frontend
netshape run --profile 3g -- npx electron .

# Terminal 2 — Python backend
netshape run --profile 3g -- python -m uvicorn app.main:app

What Doesn't Work

Traffic typeExampleWhy
Raw TCP socketsSelf-hosted Redis, MongoDB driverNot HTTP
UDPDNS, VoIP, game servers, QUICNot TCP/HTTP
WebRTCVideo calls, peer-to-peerUDP/DTLS
gRPC (some configs)gRPC over HTTP/2 worksDepends on transport
Browser-side trafficChrome/Firefox without system proxyBrowser ignores env vars

Data & Logs

Log Files

netshape run --profile 3g --log-file proxy.log -- python app.py

Each line is a JSON object. Log files rotate at 10 MB, keeping 3 backup files.

Persistence

Rules

Automatically saved to ~/.netshape/rules.json. Restored on new sessions — always in disabled state.

User Scenarios

Scenario files saved to ~/.netshape/scenarios/ are automatically discovered.

FAQ

Do I need to change my app's code?

For most apps — no. Python, Node.js, Go, Ruby, and PHP HTTP clients all respect HTTP_PROXY env vars automatically. Electron apps require a one-time code change.

Will NetShape throttle LLM streaming responses?

Yes. Streaming token responses are especially interesting to throttle — tokens trickle in slowly under low bandwidth, and high latency delays the first token. No code changes needed for any Python or Node.js OpenAI/Anthropic SDK.

Can I run multiple sessions at the same time?

Yes — one per service, each in its own terminal. Each session auto-selects its own proxy port (8090, 8092, 8094, ...) and control port (8091, 8093, 8095, ...).

Can I use NetShape in CI?

Yes. Run your test command through NetShape — netshape run --profile 3g -- pytest. The session exits automatically when the test finishes.

NetShape v1.0.1 — MIT License