How WireLens captures traffic
What happens between your app and the server on Mac, iPhone, iPad and Android, and what WireLens can and cannot see.
WireLens sits between your app and the network. How it gets there differs by platform, because macOS, iOS and Android allow different things. What it records is the same.
For every connection, WireLens does one of two things:
- Plain HTTP is read, passed on, and recorded as it goes by.
- HTTPS starts with a handshake for a host. For a host you have not chosen to decrypt, WireLens passes the connection through untouched and records a
CONNECTrow. For a host on your SSL Proxying list, WireLens answers the handshake itself with a certificate for that host, reads the exchange, and makes its own secure connection to the server.
On the Mac#
- WireLens runs a proxy inside the app, on
127.0.0.1:9090by default. The port is in Settings ▸ Capture. - With Set as the macOS system proxy on (the default), macOS sends web traffic to that proxy while capture runs. Browsers, most native apps and anything built on URLSession follow that setting. Stopping capture or quitting puts your network settings back.
- With the switch off, only clients you point at the listener are captured: phones, virtual machines,
curl --proxy. - Tools that ignore the macOS proxy setting, such as many command line tools and containers, take two environment variables instead. See Client setup.
- The opt-in Network Extension (Experimental) in Settings ▸ Capture captures every app on the Mac, including apps that ignore proxy settings. It needs macOS 15 or later and your approval in System Settings. While it is on, the system proxy is off. See Install on Mac.
- WireLens's own connections to servers go straight out, never back through the proxy.
- Each flow shows which app on your Mac made it. Simulators and Android emulators appear under Remote Devices in the sidebar.
- Traffic to
localhostis captured like any other. Some apps still skip the proxy forlocalhostand private addresses because of the macOS proxy exceptions list. Pointing the client at the proxy explicitly always works:curl -x http://.127. 0. 0. 1: 9090 http:// localhost: 3000/
Intel Macs cannot decrypt. They capture HTTPS as CONNECT tunnels, with a banner that says so.
On iPhone and iPad#
iOS does not let one app send other apps through a proxy. WireLens uses a VPN configuration that runs entirely on the device instead:
- When capture starts, iOS hands the device's traffic to WireLens on the phone.
- Web traffic goes to WireLens's proxy on the phone. On other ports, WireLens recognises HTTP and TLS and treats them the same way. Anything else passes through.
- WireLens connects to the real servers from the phone. There is no WireLens server in the path and nothing is sent to us.
- DNS lookups go to Google Public DNS while capture runs.
- QUIC is dropped by default. Apps that would use HTTP/3 fall back to TCP, where WireLens can decrypt them. Decrypting HTTP/3 in place is an experimental switch.
- Bodies are written to storage as they arrive, up to Settings ▸ Capture ▸ Body Capture Limit (5 MB by default, per request and per response). Larger bodies are kept truncated and marked that way.
On Android#
Android works the same way as the iPhone, with a local VPN on the device:
- When capture starts, Android hands the device's traffic to WireLens on the phone. You allow the VPN once, in the Setup Guide.
- Tools ▸ Apps chooses which apps are captured. A change applies the next time capture starts.
- WireLens connects to the real servers from the phone. Nothing goes through a WireLens server.
- Each flow shows the app and package that made it.
- QUIC is dropped by default, and apps fall back to HTTP/2 or HTTP/1.1 over TCP. Decrypt HTTP/3 (Experimental) is in Tools.
- Bodies are kept in full, up to 512 MB each, streamed to storage.
- Android lets each app decide whether to trust a certificate you installed. Chrome and other browsers do. Most other apps show as connections only (host, app, size and timing) unless they opt in. See Things Android decides.
What WireLens can and cannot see#
| Traffic | What you get |
|---|---|
| Plain HTTP | Everything |
| HTTPS, host on the SSL Proxying list, certificate trusted | Everything |
| HTTPS, host not on the list | Host, port, timing and byte counts, as a CONNECT row |
| Apps that pin their certificates | The tunnel only. Decrypting them makes the app refuse to connect. |
| Android apps that do not trust user certificates | The tunnel only, as for pinned apps |
| HTTP/3 over QUIC | Dropped by default, and the client falls back to TCP. With the experimental Decrypt HTTP/3 on, everything for hosts on the list. |
| Mac apps that ignore the macOS proxy setting | Nothing until you point them at WireLens or turn on the Network Extension |
What the status column reports#
When an exchange fails, the status column shows what actually happened: the connection was refused, the response was cut short, a breakpoint aborted it, the Block List stopped it. A status code appears only when your app received one. gRPC and GraphQL get the same treatment for the failures they report inside a 200.
Something here is unclear, or wrong for your setup? Contact support or write to support@wirelens.app.