Skip to content

Request Composer

The Request Composer is Ghost’s built-in API testing tool. It lets you craft HTTP requests, send them, and see the response — all without leaving Ghost. Think of it as a lightweight Postman embedded directly into your traffic inspector.

The killer feature is forking: right-click any captured flow, fork it to the composer, modify one thing (a header, a parameter, the body), send it, and instantly compare the new response with the original. This workflow is incredibly fast for debugging: “what happens if I remove the auth token?” → fork, delete the header, send, compare. Done in 5 seconds.

Three entry points:

Entry PointWhat Happens
Toolbar buttonClick the paper plane icon in the command bar. Opens a blank composer so you can build a request from scratch.
Right-click → “Fork to Composer”Right-click any flow in the traffic list and select “Fork to Composer” (git fork icon). Opens the composer pre-filled with that flow’s method, URL, headers, and body. A purple “Forked from” badge shows the original flow’s details.
macOS application menuView → Compose Request. Opens a blank composer.

When forked from a flow, Ghost loads the full flow details (headers and body) asynchronously in the background. The composer opens immediately with the basic information and fills in the details when they arrive.

The composer opens as a slide-over panel on the right side of the screen (over the flow inspector). The traffic list remains visible behind it.

┌──────────────────────────────────────────────────────┐
│ [GET ▼] [https://api.example.com/endpoint ] [⟲] [▶]│
└──────────────────────────────────────────────────────┘
  • Method selector — dropdown with 7 HTTP methods: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS
  • URL field — text input for the full URL including query parameters. Pressing Enter in this field sends the request immediately.
  • cURL import button — opens a full-screen overlay where you can paste a cURL command to populate the composer
  • Send button — paper plane icon, highlighted in cyan. Shows a spinner while the request is in flight. Disabled when the URL is empty or a request is already sending.

Keyboard shortcut: Press Cmd+Enter (macOS) or Ctrl+Enter (Windows) from anywhere in the composer to send the request.

When the composer was opened by forking a flow, a purple badge appears at the top showing the original flow’s method, status code, URL path, and duration. Click the badge to navigate back to that flow in the traffic list.

The composer has up to 4 tabs:

Headers Tab — A key-value editor for request headers. Each row has:

  • A name field (fixed width) for the header name (e.g., Authorization)
  • A value field (flexible width) for the header value (e.g., Bearer eyJhbG...)
  • A trash button to remove the row

Click “Add header” at the bottom to add a new row. When forked from a flow, headers are pre-populated — with housekeeping headers automatically excluded (host, content-length, connection, transfer-encoding), since Ghost handles those automatically.

Body Tab — A monospace text area for the request body. This is where you’d put JSON payloads for POST/PUT/PATCH requests. The placeholder shows {"key": "value"} as a hint.

Response Tab — Appears after you send a request. Shows:

  • Status badge — color-coded status code (green for 2xx, amber for 4xx, red for 5xx)
  • Duration — how long the request took in milliseconds
  • Content length — response body size
  • Response headers — complete header list
  • Response body — syntax-highlighted, with automatic JSON formatting (pretty-printed) when the response is JSON. Capped at a scrollable area (max height 400px).

Compare Tab — Only appears when BOTH conditions are met: (1) you forked from an existing flow, and (2) you’ve received a response. Shows an arrows icon to indicate comparison mode. See the Comparison section below.

Click the import button to open a full-screen overlay where you can paste a cURL command. Ghost parses it and populates the method, URL, headers, and body fields automatically.

The parser handles real-world cURL commands including complex quoting and multi-line commands. Supported flags:

FlagWhat It Does
-X METHOD or --request METHODSets the HTTP method. Also handles combined form -XPOST (no space).
-H "Name: Value" or --header "Name: Value"Adds a request header. Can appear multiple times.
-d "data" or --data "data"Sets the request body. Also supports --data-raw and --data-binary. Automatically changes the method to POST if it was GET.
-u user:pass or --user user:passConverts to a Basic Authorization header (base64-encoded).
-A "agent" or --user-agent "agent"Sets the User-Agent header.
-b "cookies" or --cookie "cookies"Sets the Cookie header.
-e "url" or --referer "url"Sets the Referer header.
--url "url"Explicitly sets the URL (alternative to positional argument).
--compressed, -s, -k, -v, -L, -iRecognized and silently skipped (they don’t affect the HTTP request structure).

The tokenizer handles single-quoted strings, double-quoted strings with backslash escapes, $'...' ANSI-C quoting, and line continuation (\ followed by a newline — common when copying multi-line cURL commands from documentation).

If parsing fails, an error message appears in the overlay explaining what went wrong.

When you fork a flow and then send a modified version, the Compare tab lets you see exactly what changed between the original response and the new one. This is the composer’s most powerful feature.

SectionHow It’s Compared
Status codeSide-by-side display of original vs. new status. A “Changed” badge appears if they differ — this is the first thing you check.
TimingOriginal vs. new duration with percentage change. Highlighted green if faster (improvement) or yellow if slower (degradation), but only when the difference exceeds 5%.
HeadersCase-insensitive header comparison. Each header is color-coded: green dot (added in new response), red dot (removed), yellow dot (value changed). Uses the same diff library as flow comparison.
BodyFor JSON responses: recursive structural diff that walks every field at every nesting level (up to 10 levels deep). Shows the JSON path (e.g., data.user.email), old value, and new value for every difference. For non-JSON: simple string comparison.

A summary badge at the top says either “Responses are identical” (nothing changed) or “N differences found” (with the count).

If the original flow was loaded as a summary (without full headers and body), a warning appears: “Original flow details are partial — select the flow in the traffic list first for accurate comparison.”

Ghost has two ways to re-send a request, and they serve different purposes:

FeatureReplayCompose
How to accessRight-click → “Replay Request”Right-click → “Fork to Composer”
Editable?No — re-sends the exact same request, byte for byteYes — you can change anything before sending
Saved to database?Yes — creates a new flow tagged replay and replay-of:{original_id}No — the response is ephemeral (disappears when you close the composer)
Shows in traffic list?Yes — appears as a new flow you can inspectNo — only visible in the composer’s Response tab
Response body cap10 MB1 MB
Use case”Did the server behavior change?” (exact reproduction)“What happens if I change X?” (experimentation)

There is also a batch replay option that replays up to 100 flows sequentially with a configurable delay between each request (0-10,000 ms). Each replayed flow gets tagged with batch-replay.

LimitValueWhy
Request body size2 MBPrevents accidentally sending enormous payloads
Response body cap1 MBKeeps the composer UI responsive (large responses are truncated)
Request timeout30 seconds (default), 60 seconds (maximum)Prevents requests from hanging indefinitely
URL schemeOnly http:// and https://No file://, ftp://, or other schemes
SSRF protectionDNS-level blocking of loopback, private, and link-local IP addressesPrevents the compose endpoint from being used to probe internal networks. However, this is intentionally more permissive than typical SSRF guards since the composer is a user-initiated testing tool.
Binary responsesAutomatically base64-encoded before returning in JSONPrevents JSON serialization errors for image, protobuf, or other binary responses

Debug a failing request — A POST to /api/checkout returns 400. Fork it, look at the body — maybe a required field is missing. Add the field, send, get 200. You’ve identified the issue.

Test authorization — Fork a request that works. Remove the Authorization header. Send. Does the server correctly return 401? Or does it leak data? This is a basic security check any QA engineer can do.

Compare environments — Copy a cURL command from staging documentation, import it into the composer, change the host to production, send. Compare the responses to verify API parity.

Modify and re-test — A search endpoint returns wrong results. Fork the request, change the query parameter, send. Compare the response body to see exactly which results changed.

Header experimentation — Add an Accept-Language: tr header to see if the API returns Turkish content. Add X-Debug: true to see if the server includes debug information in the response.