What WiretapKMP Actually Solves That Chucker and Wormholy Never Could

WiretapKMP is a KMP network inspector that does what nobody bothered to do before: ship one library that covers Ktor, OkHttp, and URLSession under the same API, with a shared Compose Multiplatform UI, built-in mocking, and a no-op strategy that leaves zero fingerprints in production. Chucker is Android-only. Wormholy is iOS-only. Both are passive log viewers with no mocking, no throttling, no cross-platform story. WiretapKMP is the answer to the question why do I need three tools to debug one app?


TL;DR: Quick Takeaways

  • Single library replaces Chucker + Wormholy + a separate mock server — works across Android, iOS, and desktop.
  • No proxy server involved — SSL pinning stays intact, no Charles/Fiddler setup, no certificate gymnastics.
  • Active debugging: mock 500s, inject latency, simulate flaky connections — not just passive traffic observation.
  • Conditional no-op dependency ensures the debugger ships zero code and zero overhead to production builds.

Multi-Client Integration: Dissecting Wiretap-Ktor, Wiretap-OkHttp, and URLSession

The architecture here is deliberately non-invasive. wiretap-ktor registers as a standard Ktor plugin — it hooks into the pipeline the same way any other feature would, no subclassing, no wrapping. wiretap-okhttp installs as an OkHttp interceptor, which means it fits into any existing OkHttp-based stack without restructuring a single line of client configuration. On iOS, wiretap-urlsession wraps URLSession at the protocol level, intercepting traffic before it hits the network layer. The key architectural decision across all three: no proxy server. This is not a minor convenience — it is a structural advantage. Proxy-based tools like Charles or Fiddler require disabling SSL pinning or installing root certificates, which breaks real-world security configs and introduces a gap between what you debug and what ships. WiretapKMP intercepts traffic in-process, so SSL pinning, certificate transparency, and network security configs behave exactly as they do in production. Youre debugging the actual app, not a neutered version of it. For teams that treat security as a first-class concern — and by 2025 that should be everyone — this distinction matters a lot.

// Ktor client setup — wiretap-ktor as a plugin
val client = HttpClient {
    install(WiretapPlugin) {
        enabled = BuildConfig.DEBUG
    }
}

// OkHttp — wiretap-okhttp as an interceptor
val client = OkHttpClient.Builder()
    .addInterceptor(WiretapInterceptor())
    .build()

Both integrations follow the same pattern: zero changes to how the HTTP client is constructed, one extra line to wire in the interceptor. The plugin-based approach means WiretapKMP doesnt own your HTTP client — it observes it. Request/Response payloads, HTTP headers, TLS details, status codes, WebSocket frames — all captured without redirecting traffic through an external process. Monitoring WebSocket traffic in Kotlin Multiplatform is historically annoying with proxy tools because WebSocket upgrade handshakes dont always play nice with MITM setups. In-process interception sidesteps that entirely.

Related materials
Distributed Systems Resilience Patterns...

Distributed Systems Resilience Patterns This guide is for backend engineers working with microservices and distributed systems. Reliability in modern engineering is not about preventing errors; it’s about managing the inevitable chaos. If you are building...

[read more →]

Adaptive UI via Compose Multiplatform: Rethinking the Debugger UX

Most debugging UIs are afterthoughts. Chuckers notification-drawer approach was clever for 2018 Android; by now it feels like reading server logs through a mail slot. WiretapKMP ships a Compose Multiplatform debugger with an adaptive list-detail layout — compact single-panel on phone, split-pane on tablet and desktop. This matters more than it sounds. When youre chasing a race condition across 12 concurrent requests, being able to see the request list and the full response body side by side without tapping back and forth is the difference between five minutes of debugging and twenty-five. The UI surfaces status codes, timing, headers, and payload in a structured view — not a raw log dump. On desktop, where KMP is increasingly relevant, the wide-format list-detail view actually makes sense ergonomically.

The Compose Multiplatform bet here is also a maintenance argument. One UI codebase, rendered natively on Android, iOS, and desktop via the same Compose runtime. No SwiftUI twin to keep in sync. No separate Android XML layout collecting dust. For a debugging library that needs to ship fast and stay current, this is the right call architecturally — even if Compose Multiplatform on iOS still has rough edges that any honest engineer will admit are real.

API Response Mocking and Throttling: Moving Beyond Passive Logging

Passive logging is table stakes. The more interesting question is: can your debugging tool become a testing tool? WiretapKMPs answer is yes, via API response mocking and network throttling baked into the same interface. You can intercept any request and return a custom response — a 500 with a specific error body, a 429 with retry headers, a malformed JSON payload — without spinning up a mock server, without touching backend code, without a staging environment. This is an in-app mock server that lives inside the debug build.

// Define a mock rule for a specific endpoint
WiretapMock.rule {
    matchUrl = "https://api.example.com/user/profile"
    responseCode = 500
    responseBody = """{"error": "internal_server_error"}"""
    delayMs = 2000 // simulate latency
}

The latency injection side is what QA engineers will actually get excited about. Simulating bad network conditions in KMP — 3G speeds, packet loss patterns, high-jitter environments — without a throttling proxy or a dedicated device profile is genuinely useful. Most apps are built and tested on fast Wi-Fi and break silently on real-world mobile connections. Network throttling for mobile debugging at the library level means you can replicate a 400ms API response without leaving your desk or reconfiguring the OS network settings. The mocking layer also lets you test edge cases that the real API might never return reliably — expired tokens, partial responses, corrupted payloads. Intercepting and mocking HTTP requests in KMP without a separate toolchain is where WiretapKMP moves from nice to have into this should be in the standard stack.

Related materials
Software Observability vs Logging...

Beyond the Console: Mastering Software Observability to Kill the Debugging Nightmare Let’s be real: if your primary debugging tool is a console.log() or a print() statement followed by the word "HERE," you aren't an engineer;...

[read more →]

Production Safety and the No-Op Strategy in KMP Builds

Every debugging library ships with the same existential risk: what happens when it leaks into production? The standard answer is dont do that, which is not an answer. WiretapKMP handles this with a no-op dependency pattern — a separate artifact that exposes identical API surface but does nothing. No interceptors registered. No UI. No retained traffic data. No runtime overhead. The KMP builds switch between the real implementation and the no-op via conditional Gradle dependencies, scoped to build variant.

// build.gradle.kts — conditional dependency by variant
dependencies {
    debugImplementation("io.wiretap:wiretap-ktor:x.x.x")
    releaseImplementation("io.wiretap:wiretap-ktor-noop:x.x.x")
}

The wiretap-ktor-noop artifact is not a stripped-down version of the real library — it is a hollow shell with the same interface, compiled to nothing meaningful. Zero overhead debugging in KMP is not a marketing line here; its a verifiable claim. The release binary contains none of the interceptor logic, none of the Compose UI, none of the mock engine. The no-op pattern also means the API call sites in your codebase dont need `if (BuildConfig.DEBUG)` guards scattered everywhere — the dependency graph handles the switch at compile time. This is how conditional dependencies in KMP builds should work, and its one of those details that separates a library built by engineers whove shipped production apps from one built by engineers who havent.

FAQ

What makes WiretapKMP different from using Chucker and Wormholy together?

Chucker and Wormholy are platform-specific tools with no shared API, no shared UI, and no mocking capability. You get two separate integrations to maintain, two separate UIs to context-switch between, and still no way to mock responses or throttle network conditions in either. WiretapKMP covers Android, iOS, and desktop in one dependency tree, with one UI and an active testing layer built in.

Related materials
A Guide to Professional...

The Art of the Post-Mortem: Why Your Worst Bugs are Your Best Teachers You’ve just spent six hours staring at a terminal, caffeine vibrating in your veins, watching your production environment burn. You finally found...

[read more →]

Does WiretapKMP require a proxy server for network inspection?

No — and this is a core design decision, not a missing feature. No-proxy network debugging means the library intercepts traffic in-process, inside the running app. SSL pinning, certificate transparency, and platform network security configs all remain active. You are inspecting the real network stack, not a proxy-modified version of it.

How does the wiretap-ktor setup affect existing Ktor client configuration?

The wiretap-ktor plugin installs into the Ktor pipeline as a standard feature — it requires no changes to how the HttpClient is constructed. One `install(WiretapPlugin)` block is the full integration cost. It does not wrap or replace the client; it observes requests and responses as they pass through the existing pipeline.

Can WiretapKMP intercept WebSocket traffic in Kotlin Multiplatform apps?

Yes. Because WiretapKMP operates in-process rather than through a proxy, WebSocket upgrade handshakes and frame-level traffic are captured without the MITM complications that proxy-based tools introduce. Monitoring WebSocket traffic in Kotlin Multiplatform apps is handled the same way as standard HTTP — no additional configuration required.

How does the no-op dependency guarantee zero overhead in production builds?

The wiretap-ktor-noop artifact is a separate compiled artifact that implements the same interface with empty method bodies. When the release variant resolves the no-op dependency, the interceptor registration, the Compose UI, and the mock engine are all absent from the binary. There is no runtime check, no disabled flag — the code simply does not exist in the production build.

Is WiretapKMP production-ready for teams with strict security requirements?

The in-process interception model is specifically better for security-conscious teams than proxy-based alternatives. SSL pinning is never bypassed, and the no-op dependency ensures the inspection layer has zero presence in production. That said, any debugging tool in a debug build carries inherent risk — traffic visibility means sensitive data visibility, and teams should evaluate their debug build distribution and signing practices accordingly.

Written by: