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 frames✅✅Feature parity
WebSocket lifecycle✅ start/end/error✅Feature 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_variables—Scripts can read rule results
npm / pip packages✅ esbuild bundle✅ pipDifferent packaging model
DNS/TCP/UDP layer hooks—✅mitmproxy covers lower layers
TLS clienthello hook—✅mitmproxy is more direct for SNI-style use
Streaming body chunk edits—✅RelayCore 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, prefer rule MockResponse or MCP mock_url 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 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