vs mitmproxy

If you have used mitmproxy Python addons, this page compares RelayCore scripting hooks, data models, and tooling. See Scripting API for reference and Scripting Guide for patterns.

Capability comparison

CapabilityRelayCoremitmproxyNotes
HTTP request/response hooks✅ 4 hooks✅ 4 hooksFeature parity
WebSocket message framesFeature parity
WebSocket lifecycle✅ start/end/errorFeature parity
Connection hooks✅ onConnect/onDisconnect✅ clientconnect/clientdisconnectRelayCore supports connection drop
Error callback✅ onError✅ errorRelayCore includes stage info
Cross-request state✅ sharedState✅ Python globalsDifferent model: per-isolate vs process-global
Environment variables✅ relay.env + whitelist✅ os.environRelayCore requires --script-env-allow
Logging✅ console.* → tracing✅ loggingFeature parity
Execution metrics✅ Prometheus✅ addon traceRelayCore via /api/v1/metrics
Built-in utilities✅ relay.*✅ Python stdlibLanguage ecosystem difference
Sub-requests✅ relay.fetch (optional)✅ requests/httpxmitmproxy HTTP client is more flexible
Rule match context✅ matched_rules / rule_variablesScripts can read rule results
npm / pip packages✅ esbuild bundle✅ pipDifferent packaging model
DNS/TCP/UDP layer hooksmitmproxy covers lower layers
TLS clienthello hookmitmproxy is more direct for SNI-style use
Streaming body chunk editsRelayCore currently reads/writes full bodies

Migration examples

Modify request headers

# mitmproxy
def request(flow):
    flow.request.headers["X-Custom"] = "value"

# RelayCore
globalThis.onRequestHeaders = (_ctx, flow) => {
  flow.layer.data.request.headers.push(["X-Custom", "value"]);
  return flow;
};

Mock responses

mitmproxy can synthesize responses in the response hook. In RelayCore 0.5.x, prefer rule MockResponse for static mocks; use scripts for dynamic logic. See the Rule Guide.

# mitmproxy
def response(flow):
    if flow.response.status_code == 404:
        flow.response = http.Response.make(200, b"OK", {"Content-Type": "text/plain"})

# RelayCore — rule example (JSON)
{
  "filter": { "type": "Url", "config": { "mode": "Contains", "value": "/missing" } },
  "actions": [{ "type": "MockResponse", "config": { "status": 200, "body": "OK" } }]
}

Key differences

  • Language: TypeScript (Deno/V8) vs Python
  • Headers: RelayCore uses [key, value][] arrays (duplicate headers preserved); mitmproxy uses dicts
  • Body: RelayCore body.content is base64 — decode with atob(), encode with btoa()
  • Flow shape: HTTP data lives under flow.layer.data.request / response (see Scripting API)
  • Global state: RelayCore sharedState.get/set vs mitmproxy module-level Python variables
  • Loading: relay-core-cli run --script, HTTP POST /api/v1/script, Tauri load_script

When to use which

ScenarioBetter fit
Daily HTTP/HTTPS capture and header/body editsEither
Python ecosystem and pip dependenciesmitmproxy
TypeScript / npm with a Rust proxy stackRelayCore
Rule + script coordination (match context in scripts)RelayCore
Transparent proxy TCP/UDP/DNS scriptingmitmproxy
Same runtime across CLI, HTTP API, MCP, desktop embedRelayCore