← Back to Blog

Why Localhost Traffic Isn't Showing in Your Proxy on macOS

· 9 min read

You start a local API on 127.0.0.1:3000, point a client at it, and the request works — status 200, body returned. But your macOS proxy debugger stays empty. No row appears in Rockxy, so there is nothing to inspect.

This is the most common first-hour surprise with any HTTP debugging proxy, and it is not a bug. Requests to localhost and 127.0.0.1 take a loopback path that skips the proxy by design. The outcome of this guide is a captured local flow: after a couple of small changes, your 127.0.0.1 request shows up in Rockxy with full method, URL, headers, body, response, and timing.

Why loopback bypasses the proxy

A proxy can only show you a request that is actually sent to it. Loopback traffic usually is not, for two independent reasons:

  1. The system proxy excludes loopback. macOS network proxy settings, and most clients that read them, treat localhost, 127.0.0.1, and ::1 as "always direct." The connection never reaches the proxy port, so there is nothing to capture.
  2. Clients honor a no-proxy list. Command-line tools and HTTP libraries read NO_PROXY / no_proxy, and that list very often contains localhost,127.0.0.1. Even with a proxy configured, the loopback host is skipped.

The fix is not to fight the operating system. It is to make one specific client send the local request through Rockxy on purpose. Rockxy is a local proxy on your Mac, so routing loopback traffic to it is a matter of client configuration, not system-wide changes.

What you will need

  • Rockxy on macOS 14 (Sonoma) or later. It is a native app; download it from the Rockxy download page.
  • A local service you can hit on a known port — for example an API on 127.0.0.1:3000. Any framework works; the port is what matters.
  • A terminal, so you can run one request with explicit proxy settings.
  • Two ports clear in your head from the start: the app port (your service, e.g. 3000) and the proxy port (Rockxy's listener, shown in its toolbar). Swapping these two is the single most common mistake.

Step 1 — Confirm Rockxy is capturing and read its proxy port

Start Rockxy and make sure capture is enabled. Read the active proxy port from the toolbar; the examples below assume 8888, but yours may differ. Use whatever value Rockxy shows.

Send one request you know Rockxy should see — a plain external HTTPS URL routed through the proxy port — so you have proof the listener is alive before you touch loopback:

curl -x http://127.0.0.1:8888 https://api.github.com/zen

What you should see in Rockxy: a new row for api.github.com. If even this does not appear, the proxy port is wrong or capture is off — fix that before going further, because no loopback trick will help until the listener itself receives traffic.

Step 2 — Reproduce the empty capture

Now do the thing that fails, so you can watch it fail. Hit your local service the normal way:

curl http://127.0.0.1:3000/api/health

The request succeeds in the terminal, but no row appears in Rockxy. That is the loopback bypass in action: curl connected straight to 127.0.0.1:3000 without consulting the proxy. Confirming the miss now means you can trust the fix in the next step.

Step 3 — Route the loopback request through Rockxy explicitly

Send the same request, but tell the client to use Rockxy as its proxy and stop excluding the loopback host. With curl, that is the -x flag plus an empty --noproxy list:

curl -x http://127.0.0.1:8888 --noproxy "" http://127.0.0.1:3000/api/health

Two things are happening. -x http://127.0.0.1:8888 forces the request onto Rockxy's proxy port instead of a direct connection. --noproxy "" clears the exclusion list so 127.0.0.1 is no longer treated as "always direct." Rockxy then forwards the request to your service on 3000 and records both sides.

The same idea maps to any HTTP client. For a library that reads environment variables, set the proxy and clear the no-proxy list for the run:

export HTTP_PROXY="http://127.0.0.1:8888"
export HTTPS_PROXY="http://127.0.0.1:8888"
export NO_PROXY=""

# run your client here — e.g. a Node, Python, or Go script

Not every library honors these variables the same way, so explicit per-client proxy options are the most reliable choice for reproducible debugging. The framework-specific setups are covered in the Node.js and Python guides; the loopback rule is identical in both — route explicitly and clear NO_PROXY for the local host.

What success looks like in Rockxy

After Step 3, the traffic list shows a row for 127.0.0.1/api/health. Selecting it reveals GET 200 OK http://127.0.0.1:3000/api/health, the request headers your client sent, the response body, and timing. The screenshot below shows the same shape for a local Node service captured on 127.0.0.1 — the loopback request is now visible end to end.

Rockxy capturing a localhost 127.0.0.1 request on macOS with the request URL, headers, and response body visible after the client was routed explicitly through the proxy.
A loopback request captured in Rockxy after the client was pointed explicitly at the proxy port. The selected flow proves the client, the proxy, and the local service on 127.0.0.1 are wired together.

This is the baseline. Once one boring local request is visible, every harder question — wrong base URL, a missing token, a bad JSON shape, a slow route — has far fewer places to hide.

An alternative: use a non-loopback hostname

If you would rather not pass proxy flags on every command, give your local service a hostname that is not on the loopback fast path. Map a custom name to 127.0.0.1 in /etc/hosts:

# /etc/hosts
127.0.0.1   devbox.test

Then call http://devbox.test:3000/api/health instead of http://127.0.0.1:3000/.... The host still resolves to your machine, but because it is not literally localhost or 127.0.0.1, clients that only exclude those two names will send it through the proxy. This is handy for browsers, which are the most aggressive about short-circuiting loopback. Keep the hostname off the no-proxy list, and prefer a name you control rather than a real public domain.

Capturing HTTPS on localhost

Everything above assumes plain HTTP, which is the right way to prove routing first. If your local service is HTTPS, one more thing has to be true: the host must be inside Rockxy's SSL Proxying scope, and the client must trust Rockxy's certificate path. Without that, you will still see a row, but it will be a tunnel with no decrypted body.

What you should see in Rockxy: for a decrypted HTTPS request, the selected flow shows a readable request and response body. If instead you see a CONNECT or tunnel-only row, the proxy path exists but decryption did not happen — enable HTTPS decryption for that host and confirm certificate trust. The mechanics are covered in How to Debug HTTPS Traffic on macOS and, for how the interception works, How Rockxy Intercepts HTTPS Without Compromising Security. The certificate steps live in the certificates and trust docs.

If it does not work

Still no row after adding -x. The client is still connecting directly. Check that NO_PROXY / no_proxy is cleared for the host, that you used Rockxy's current toolbar port, and that the tool actually honors proxy settings. Some clients ignore both the system proxy and the environment variables and need an explicit in-code proxy option.

You see Connection refused to the proxy port. The port in your command does not match Rockxy's listener. Re-read the toolbar value and rerun. This usually means the proxy port drifted after a restart.

The request now fails when it used to succeed. You may have swapped the two ports — sending traffic to the app port as if it were the proxy, or vice versa. In the examples, 3000 is the service and 8888 is Rockxy. The client connects to the service through the proxy, so the proxy goes in -x and the service URL stays as the target.

A tunnel row appears but the HTTPS body is unreadable. That is TLS, not routing. Add the host to SSL Proxying scope and trust the certificate. If the local server pins its certificate, Rockxy will not silently defeat that — a pinned or failed handshake is surfaced as a failed transaction in the request list so you can see it happened, rather than being decrypted.

Your "localhost" is inside a container. From inside a Docker container, localhost is the container, not your Mac, and the container has its own proxy configuration. Point the containerized client at the host address your platform exposes and set the proxy variables inside the container, not just on the host.

Inspect the captured flow with your AI assistant (optional)

Once the local request is captured, you can let an MCP-capable AI tool read it directly instead of pasting terminal output into a chat. Rockxy ships a built-in local MCP server that exposes read and replay tools — list_flows, get_flow_detail, replay_request, and diff_flows — so an assistant like Claude or Cursor can ask "what did that localhost request actually send?" against the real capture.

Local MCP is 100% free and unlimited in the Free tier. No license upgrade required. The workflow is local-first and user-controlled: Rockxy's MCP server binds to localhost, and captured data stays in a local store on your Mac. Rockxy itself never uploads your traffic to an AI provider. If you enable the workflow, the assistant you connect may include the data it retrieves in its own prompts — that is your choice to make per tool. Setup is in the Connect Claude Desktop to Rockxy guide.

Next steps

The loopback rule is short: a proxy shows you what a client sends it, and loopback traffic is not sent there unless you ask. Route one client explicitly, clear the no-proxy list for the local host, and your 127.0.0.1 request becomes a normal captured flow.

From here, wire it into your real stack with the Node.js or Python setup guide, move to HTTPS on macOS when you need decrypted bodies, or read the traffic capture docs. If capture behaves oddly in general, the FAQ covers the most frequent setup questions.

Rockxy — native macOS proxy debugger

Try Rockxy — Free and Open Source

A native macOS proxy debugger for HTTP, HTTPS, WebSocket, and API traffic. No cloud account. No subscription. Download the app or audit the source directly on GitHub.

Open source · AGPL-3.0 · Native macOS · No account required · Source available to audit