Skip to content
PortBay

Every request to your local sites, live

PortBay tails its Caddy edge and streams each request into a DevTools-style table: method, host, path, status, latency and size, mapped to the project it hit. No setup.

GET /api/cart 200 12 ms · blog.test
POST /checkout/session 201 48 ms · stripe-cli
mysql SELECT * FROM orders 3.1 ms
GET /assets/app.css 304 2 ms
mail order-confirmation caught → Mailpit
PATCH /api/cards/42 200 19 ms · @claude
queue ProcessWebhook done · 0 retries
GET /api/board 200 8 ms · portbay
https cert renewed mkcert · trusted
POST /webhooks/stripe 200 31 ms
mysql UPDATE cards SET status 1.8 ms
GET /pricing 200 11 ms · chrome
GET /api/cart 200 12 ms · blog.test
POST /checkout/session 201 48 ms · stripe-cli
mysql SELECT * FROM orders 3.1 ms
GET /assets/app.css 304 2 ms
mail order-confirmation caught → Mailpit
PATCH /api/cards/42 200 19 ms · @claude
queue ProcessWebhook done · 0 retries
GET /api/board 200 8 ms · portbay
https cert renewed mkcert · trusted
POST /webhooks/stripe 200 31 ms
mysql UPDATE cards SET status 1.8 ms
GET /pricing 200 11 ms · chrome
Requests2.4k
Avg response14 ms
DB queries184
HTTPS100%
Mail caught36
Errors0
Cache hits92%
Uptime99.9%
Open the inspector
All services running smoothly

HTTP inspector

A DevTools-style live table of every request through the Caddy edge, with filters, header detail, opt-in body capture and a dump viewer.

The short answer

How do I see every HTTP request to my local dev site?

Read the access log of a reverse proxy sitting in front of the dev server. That is the one vantage point that catches requests the framework never sees, unlike an application log, and that survives a page navigation, unlike the DevTools Network tab. Doing it yourself means adding a proxy layer (mitmproxy --mode reverse:http://localhost:5173) and re-teaching it your hostnames and certificates. In PortBay the traffic already flows through a bundled Caddy edge, so the inspector tails Caddy's structured access log in a background thread and streams each request into a table: method, host, path, status, latency, response size and the matched project. Filter by project, errors only (status 400 and up), or a case-insensitive path search; click a row for the timestamp and every header Caddy logged. Bodies need the opt-in recording mode, because the access log carries none. A dump viewer catches Laravel and Symfony dump() output too.

Verified against the product, 2026-07-10.
In the app

Watch the traffic, keep the errors

HTTP Inspector — live
Errors only ≥ 400
GET/api/posts20012 ms

Requests stream in as Caddy serves them; one click on Errors only strips the noise and leaves the 404 you were hunting.

How it works

From page load to answer

  1. Open the Inspector
  2. Hit your project
  3. Filter to what matters
  4. Expand the row
  5. Chase a dump

Open the Inspector

No configuration. The inspector is active whenever Caddy runs; on open, the last 200 log lines backfill the table so you have context immediately.

Hit your project

Load the site, click around, fire the webhook. Rows appear in real time with method, path, status, latency, size and the matched project.

GET /api/orders/7 → 404 · 9 ms

Filter to what matters

Pick a project, toggle Errors only (status 400 and up), or substring-search path and host. Filters apply locally, no round-trips.

Expand the row

One click shows the ISO timestamp, the response size, and every request header Caddy logged. Opt-in body recording captures payloads when headers are not enough.

Chase a dump

Enable the dump viewer in Integrations and dump() or dd() calls from Laravel and Symfony land in a live, time-ordered stream with file and line; any language can POST /dump.

dump($order) → dumps view · OrderController.php:42
Spec

Inspection, tier by tier

CapabilityCommunityPro
Live request table + filtersIncludedIncluded
Header detail per requestIncludedIncluded
Opt-in body recordingIncludedIncluded

The always-on table carries no bodies; recording captures them when enabled.

Replay a captured exchangeIncludedIncluded

From the app; deliberately unavailable to CLI and MCP callers.

Dump viewer (VarDumper + POST /dump)IncludedIncluded

Opt-in from Integrations; off by default.

History1,000-entry buffer1,000-entry buffer
Without PortBay

Reconstructing a request flow by hand

Without an inspector you stitch the story together from app logs, a DevTools tab that forgets on navigation, and logging middleware you have to remember to remove.

The traffic already flows through PortBay's edge; the inspector just shows it to you, and the dump viewer catches what the framework wants to say.

Questions

Asked before downloading

Not in the always-on table: it reads Caddy's access log, which carries no body content, so live inspection stays cheap. When you need payloads, turn on the opt-in body recording and the captured exchanges include them; replay is available from the app on what was captured.

No. It tails the Caddy access log in a background thread and is active whenever Caddy is running. On first open the last 200 lines backfill the table, log rotation is detected, and Clear truncates the on-disk log when you want a clean slate.

A live, time-ordered stream for debug dumps. Laravel and Symfony dump() and dd() calls arrive over the VarDumper wire protocol through an injected VAR_DUMPER_SERVER, and any language can POST to /dump. Each entry shows a project badge, file and line, and an expandable value tree. Opt-in from Integrations.

Yes, and it pairs with tunnels: share the project on a public URL, point Stripe or GitHub at it, and watch each callback arrive with its method, status and headers. Errors-only filtering keeps the retries readable.

The in-memory buffer holds 1,000 entries (the table renders up to 500 at a time), and reopening the view backfills the most recent 200 log lines from disk. Clear empties both the buffer and the on-disk access log.

PortBay mascot — a friendly blue tugboat

Give your projects and your agents a real local home.

Download for macOS

Free & open source · macOS 11+ on Apple Silicon · Pro from $10/mo