Skip to content

Breakpoints

Breakpoints let you pause HTTP traffic mid-flight — like a debugger for network requests. When a request matches your breakpoint rule, Ghost holds it, opens a full-screen editor where you can inspect and modify every part of the request or response, and then lets you continue, modify, or drop it. The actual HTTP connection waits while you decide what to do.

This is the most powerful manual testing tool in Ghost. Want to see what happens when a request has different headers? Pause it, change the header, continue. Want to test how your app handles a 500 error? Pause the response, change the status code to 500, continue. Want to block a specific request entirely? Pause and drop it.

What this diagram shows — the complete breakpoint lifecycle:

  1. An HTTP request arrives at Ghost’s proxy from the client (browser, mobile app, etc.)
  2. The proxy checks the request against all enabled breakpoint rules
  3. If a rule matches, the flow is held — the proxy goroutine (the thread handling this request) literally blocks on a Go channel, waiting for your decision. The client’s connection stays open but no data flows.
  4. A WebSocket event (flow.breakpoint) is sent to the frontend, which opens the breakpoint editor overlay with the full request data
  5. You inspect the request — see every header, the body, the URL — and decide what to do
  6. You click one of three buttons: Continue (send it as-is), Continue Modified (apply your edits then send), or Drop (kill the request entirely)
  7. The proxy goroutine unblocks and proceeds with your decision
  8. If the request was forwarded, the response comes back from the server. If you also have a response-phase breakpoint rule, the response is held in the same way — giving you a chance to inspect and modify the response before the client receives it.

The key insight: Ghost doesn’t copy the request and let the original proceed. It actually blocks the HTTP connection. The client is genuinely waiting. This means your modifications are the real thing — the server receives exactly what you send, and the client receives exactly what you allow through.

Each rule defines when to pause traffic. You can have multiple rules active simultaneously.

FieldTypeDescription
Phaserequest or responseRequest phase pauses the flow before it reaches the server — you can modify what the server sees. Response phase pauses the flow after the server responds — you can modify what the client receives.
HostGlob patternWhich hostnames to match. Uses Go’s path.Match glob syntax: * matches any characters, ? matches a single character. Example: *.example.com matches api.example.com, cdn.example.com. Leave empty to match any host.
PathGlob patternWhich URL paths to match. Example: /api/v1/* matches /api/v1/users, /api/v1/orders. Leave empty to match any path.
MethodExact matchWhich HTTP method to match (case-insensitive). Example: POST matches only POST requests. Leave empty to match any method.
EnabledToggleDisabled rules are skipped without being deleted — useful for temporarily turning off a breakpoint without losing the pattern.

All conditions must match. A rule with host *.api.com and method POST only pauses POST requests to hosts ending in .api.com. A rule with all empty patterns pauses all traffic for that phase — use with caution.

If you don’t take any action within 30 seconds, the flow is automatically continued unmodified. This safety mechanism prevents the proxy from stalling indefinitely if you forget about a held flow or switch away from Ghost.

The countdown is visible in the breakpoint editor:

  • Starts at 30 seconds, counts down every second
  • Turns amber at 10 seconds remaining
  • Turns red with a pulsing animation at 5 seconds remaining
  • At 0, the flow is released with a timeout action

When a flow is held, a full-screen overlay (z-index 200, covering the entire viewport) appears with the held flow’s data. The overlay has a dark, translucent backdrop so you can still see the traffic list behind it.

┌─────────────────────────────────────────────────────────┐
│ ⚠ Breakpoint Hit [Request] POST /api/v1/cart/add │
│ ● ● ○ │
├─────────────────────────────────────────────────────────┤
│ │
│ Method: [POST ▼] URL: [https://api.example.com/...] │
│ │
│ [Headers] [Body] │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Authorization: Bearer eyJhbG... [×] │ │
│ │ Content-Type: application/json [×] │ │
│ │ X-Custom: test-value [×] │ │
│ │ [+ Add header] │ │
│ └─────────────────────────────────────────────────┘ │
│ │
├─────────────────────────────────────────────────────────┤
│ Auto-continue in 24s [Drop] [Continue] [Modified] │
└─────────────────────────────────────────────────────────┘

A warning-colored banner showing:

  • “Breakpoint Hit” label
  • Phase badge — “Request” (cyan) or “Response” (purple)
  • HTTP method and full URL of the held flow
  • Dot indicators when multiple flows are held simultaneously — click to switch between them

When a request-phase breakpoint fires, you can modify:

FieldEditorWhat You Can Do
MethodDropdownChange GET to POST, PUT to DELETE, etc. (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS)
URLText inputChange the destination URL entirely — redirect to a different server, modify path or query parameters
HeadersKey-value editorAdd new headers, remove existing ones, or change values. Each row has a delete button, and there’s an “Add header” button at the bottom.
BodyTextareaModify the request body (monospace font for readability)

When a response-phase breakpoint fires, you can modify:

FieldEditorWhat You Can Do
Status CodeNumber inputChange the response status (e.g., change 200 to 500 to test error handling) — the status text (like “OK” or “Internal Server Error”) is automatically updated to match
HeadersKey-value editorAdd, remove, or change response headers (e.g., add a Set-Cookie header)
BodyTextareaModify the response body (e.g., change JSON values, remove fields, inject test data)

Three actions at the bottom of the editor:

ActionButton ColorWhat It Does
DropRed (Prohibit icon)Terminates the flow entirely. The request is NOT forwarded to the server (for request phase) or the response is NOT delivered to the client (for response phase). The connection is closed.
ContinueGreen (Play icon)Releases the flow without any modifications. The original request/response proceeds as if the breakpoint never fired.
Continue ModifiedAmber (Pencil icon)Applies all your edits to the flow, then releases it. The server receives your modified request, or the client receives your modified response.

If multiple requests match your breakpoint rule simultaneously (e.g., a page load that triggers several API calls at once), Ghost holds all of them. Dot indicators in the top banner show how many flows are held, and you can switch between them. Each flow has its own independent 30-second timeout.

The breakpoint rules panel also shows a pending flows strip at the bottom when flows are held, with quick Continue and Drop buttons for each — useful when you want to quickly release several held flows without opening the full editor for each one.

Breakpoints run first in the interceptor pipeline:

Breakpoints → Map Rules → Addons → Storage → Security

This positioning is intentional:

  • You see the raw, unmodified request exactly as the client sent it — before any map rules rewrite URLs or addons modify headers
  • Your breakpoint edits are visible to all downstream interceptors — if you change a URL in a breakpoint, map rules will match against the modified URL, addons will see the modified URL, and the modified version is what gets stored in the database
  • Response-phase breakpoints fire after the response passes through all other interceptors, so you see the final response that would be delivered to the client

Manage your breakpoint rules from the slide-over panel (accessible from the toolbar). The panel shows:

  • Rule list — each rule displays its phase (Request/Response badge), method badge, host and path pattern, and an enabled/disabled toggle. Delete button appears on hover.
  • Add rule form — select phase (Request or Response), enter host glob, path glob, and method (dropdown with Any, GET, POST, PUT, PATCH, DELETE)
  • Pending flows strip — when flows are currently held, they appear at the bottom with quick Continue and Drop buttons
  • Clear all button — removes all rules at once

Breakpoint rules are not saved to the database. They exist only in memory and are cleared when Ghost restarts. This is intentional — breakpoints are debugging tools for your current session, not permanent configuration like map rules. If you need persistent traffic modification, use Map Rules instead.

EventWhen It FiresPayload
flow.breakpointA flow is held by a matching ruleFull flow data: flow ID, phase, method, URL, host, path, headers, body. For response phase: also includes status code, response headers, and response body.
flow.resumedA held flow is released (by user action or timeout)Flow ID and the action that was taken: continue, modify, drop, or timeout
MethodEndpointDescription
GET/api/v1/breakpointsList all breakpoint rules
POST/api/v1/breakpointsCreate a new rule (auto-generates a ULID if no ID provided, defaults phase to “request”)
PUT/api/v1/breakpoints/{id}Update a rule
DELETE/api/v1/breakpoints/{id}Delete a rule
POST/api/v1/breakpoints/{id}/toggleToggle a rule’s enabled state
DELETE/api/v1/breakpointsClear all rules at once
POST/api/v1/breakpoints/resume/{flowID}Resume a held flow with a resolution (action + optional modifications)

The resume endpoint accepts a JSON body specifying what to do with the held flow:

{
"action": "continue",
"method": "POST",
"url": "https://modified.example.com/new-path",
"headers": { "Authorization": "Bearer new-token" },
"body": "{\"modified\": true}",
"status_code": 200,
"response_headers": { "X-Custom": "value" },
"response_body": "{\"result\": \"modified\"}"
}
  • action is required: continue, modify, or drop (defaults to continue if empty)
  • Request fields (method, url, headers, body) are only used when action is modify and the phase is request
  • Response fields (status_code, response_headers, response_body) are only used when action is modify and the phase is response
  • Returns 404 if the flow is no longer held (already timed out or already resumed)

Debug what the client is sending — Set a request breakpoint on POST /api/checkout. When the checkout request fires, Ghost pauses it and shows you every header and the full body. You can verify that the client is sending the correct auth token, the right product IDs, and proper formatting — all without adding any logging.

Test error handling — Set a response breakpoint on any endpoint. When the response arrives, change the status code to 500 and the body to {"error": "Internal server error"}. Continue modified. Your app now receives a 500 error — you can verify that it shows the right error message, retries correctly, or gracefully degrades.

Inject test data — Set a request breakpoint on a search endpoint. When the request fires, modify the search query to something specific (an edge case, a unicode string, an SQL injection payload). Continue modified. See how the server handles it.

Block specific requests — Set a request breakpoint on a third-party analytics endpoint. When it fires, drop it. Your app continues without analytics — useful for testing offline behavior or verifying that analytics failures don’t break the app.

Header manipulation — Set a request breakpoint and add a custom header like X-Debug: true or remove the Authorization header. Test how the server responds to different header configurations without changing any client code.

Simulate slow responses — While a response is held at a breakpoint, wait 10 seconds before continuing. Your app experiences a slow response and you can observe how it handles the delay (loading spinners, timeouts, retry logic).