Flows & Sessions
Ghost’s data model is built around two core concepts: flows (individual captured HTTP requests and their responses) and sessions (named containers that group flows together). Understanding these concepts is essential for using Ghost effectively, because everything you see in the interface — the traffic list, the inspector, the search, the AI agent — is built on top of flows and sessions.
A flow is Ghost’s representation of a single HTTP request-response pair. Every time your browser loads a page, your mobile app fetches data from an API, or any application communicates with a server over HTTP or HTTPS, Ghost captures that communication as a flow.
A flow contains everything about that single network interaction: what was requested (the URL, method, headers, body), what came back (the status code, response headers, response body), how long each phase took (DNS lookup, connection, data transfer), and metadata about where the request came from (which device, which app, what time).
Flow Structure
Section titled “Flow Structure”The following diagram shows the internal structure of a flow — what data is stored for each captured request:
What this diagram shows: An Entity-Relationship (ER) diagram of Ghost’s flow data model. Each box represents a data structure, and the lines between them show relationships:
-
Flow — The top-level record. Contains metadata about the captured interaction: a unique ID, which session it belongs to, where the traffic came from (proxy, replay, script, or import), timing information, error details if the request failed, the source device and app information, user annotations (notes), and user/system tags. The device fields are granular —
device_typedistinguishes betweenmac,ios_simulator,ipad_simulator,ios_device,android_device,android_emulator, andunknown. -
Request — The outgoing HTTP request data. Every flow always has exactly one request (shown by the
||--||“one-to-one” relationship). Contains the HTTP method (GET, POST, etc.), the full URL, hostname, path, protocol version (HTTP/1.1 or HTTP/2), all request headers, the request body (for POST/PUT/PATCH requests), content type/length, and optional HTTP trailers. -
Response — The incoming HTTP response data. A flow may or may not have a response (shown by the
||--o|“one-to-zero-or-one” relationship) — if the server never responded (timeout, connection refused), the flow has no response. Contains the status code (200, 404, 500, etc.), status text, protocol version, all response headers, the response body, content type/length, and optional HTTP trailers. -
Timings — Performance breakdown of the request lifecycle. Also optional (zero or one). Breaks the total duration into phases: DNS lookup (converting the hostname to an IP address), TCP connect (establishing the network connection), TLS handshake (setting up encryption for HTTPS), TTFB (Time To First Byte — waiting for the server to start responding), body transfer (downloading the response body), and a total field for end-to-end duration. These timings power the Waterfall Timeline view.
Flow IDs — ULIDs
Section titled “Flow IDs — ULIDs”Every flow gets a unique identifier. Ghost uses ULIDs (Universally Unique Lexicographically Sortable Identifiers) instead of the more common UUIDs. Here’s why:
- Time-ordered — The first part of a ULID encodes the creation timestamp (down to the millisecond). This means sorting flows by their ID automatically sorts them by the time they were captured. With random UUIDs, you’d need a separate timestamp column and index for time-based sorting.
- Unique — After the timestamp, a ULID includes 80 bits of cryptographic randomness. This means even if two flows are captured at the exact same millisecond, they’ll have different IDs. Collisions are effectively impossible.
- Human-readable — ULIDs are encoded in base32, producing compact strings like
01HWRFQP6B8SYG1KQJZ5MP4TS2. They’re shorter than UUIDs and don’t contain confusing characters.
Flow Sources
Section titled “Flow Sources”Each flow records where it came from, which helps you understand the traffic context:
| Source | What It Means | Example |
|---|---|---|
proxy | Normal proxy traffic — a browser or app sent an HTTP request through Ghost’s proxy, which forwarded it to the upstream server | You browse hepsiburada.com in Chrome and Ghost captures every API call |
replay | This flow was created by replaying a previously captured flow. The original request was re-sent to see if the response changed. | You right-clicked a flow and chose “Replay” to test if an endpoint’s behavior has changed |
script | Generated by Ghost’s scripting or security testing tools (Request Attacker, AI agent security probes, injected scripts). These flows originate from automated actions, not direct user browsing. | The AI agent sent a modified version of a login request to test for SQL injection, or an injected script made a fetch call |
import | Imported from an external source like a HAR file. These flows were captured by another tool and loaded into Ghost for analysis. | You imported a HAR file exported from Chrome DevTools or another proxy tool |
Tags are string labels attached to flows for organization and filtering. Think of them like sticky notes — you can add tags to mark important flows, and then filter the flow list to show only flows with specific tags.
-
User tags — Tags you add manually via the UI (right-click a flow → Add Tag) or that the AI agent adds during analysis. You can use any text:
"important","regression-candidate","payment-flow", etc. -
System tags — Tags added automatically by Ghost’s interceptors. These have special prefixes and are used internally:
__bookmarked— You starred/bookmarked this flow for quick access_noise_suppressed:47— This flow was kept as a representative sample; the number indicates how many identical requests were suppressed by noise detection (in this example, 47 repetitive requests were condensed into this one)security:header-missing— The security interceptor found that this response is missing important security headerssource:security-test— This flow was generated by security testing, not real user traffic
Sessions
Section titled “Sessions”A session is a named collection of flows — like a folder for your captured traffic. Sessions are the primary organizational unit in Ghost. When you start a new testing task, you typically create a new session to keep that task’s traffic separate from everything else.
For example, you might have sessions named:
- “Login Flow Testing - v3.2”
- “Payment Regression Check”
- “Security Audit - User API”
- “Mobile App - iOS 17.4”
Session Properties
Section titled “Session Properties”| Property | What It Is | Details |
|---|---|---|
id | Unique identifier (ULID) | Generated automatically when the session is created |
name | The name you see in the UI | You choose this when creating the session. Can be renamed later. |
description | Optional description text | Additional context about what this session is for |
created_at | When the session was created | Shown in the session list for reference |
flow_count | Number of flows in the session | Computed field — counts flows belonging to this session |
Note on active session: The “active” session is NOT a property stored on the session itself. It’s managed separately by Ghost’s proxy server as runtime state. The proxy holds a sessionID value, and all newly captured traffic is tagged with that ID. This means the active session is a global setting — not a per-session flag — and only one session can be active at a time.
How Sessions Work
Section titled “How Sessions Work”-
One active session at a time — Ghost always has exactly one active session. All newly captured traffic (from the proxy, extension, or any other source) is automatically tagged with the active session’s ID and stored in that session. You can see which session is active in the session sidebar (highlighted) and in the command bar dropdown.
-
Switching sessions changes everything — When you switch to a different session, the entire UI updates: the flow list shows only that session’s flows, the AI agent’s context switches to that session’s conversations, the domain navigator refreshes to show that session’s hosts, and any session-specific rules (injection rules, etc.) activate.
-
Sessions are independent — Each session has its own flows, agent conversations, security findings, and browser extension interactions. This isolation means you can have a QA testing session and a security audit session running on the same Ghost instance without them interfering with each other.
-
Sessions persist across app restarts — All session data is stored in the SQLite database. When you close and reopen Ghost, all your sessions and their flows are still there. The previously active session is restored automatically.
Session Operations
Section titled “Session Operations”| What You Want to Do | How to Do It | What Happens |
|---|---|---|
| Create a new session | Click the ”+” button in the session sidebar, or call POST /api/v1/sessions via the API | A new empty session is created. It becomes the active session automatically. |
| Switch to a different session | Click a session name in the sidebar, or use the dropdown in the command bar | The flow list, agent context, and all views update to show the selected session’s data |
| Rename a session | Double-click the session name in the sidebar | An inline editor appears. Type the new name and press Enter. |
| Delete a session | Right-click the session → Delete | The session and ALL its flows are permanently deleted from the database. This cannot be undone. Ghost will ask for confirmation. |
| Export a session | Right-click the session → Export, then choose a format | Ghost exports the session’s flows as HAR (HTTP Archive, for importing into other proxy tools), JSON (for programmatic access), CSV (for spreadsheets), or Postman Collection (for importing into Postman). |
| Compare two sessions | Select two sessions using Ctrl+Click in the sidebar, then click “Compare” | Opens the Session Comparison view showing differences in endpoints, status codes, and response structures between the two sessions. |
Full-Text Search
Section titled “Full-Text Search”Ghost builds a full-text search index across all captured traffic using SQLite’s FTS5 (Full-Text Search version 5) engine. This means you can search for any text — a URL fragment, a header value, a string in a request body, an error message in a response — and get instant results, even across hundreds of thousands of flows.
The search index covers these fields (using the porter unicode61 tokenizer for stemming and unicode support):
- Request URL, host, and path — including query parameters (so searching for
user_id=123finds all requests that included that parameter) - Request and response headers — search for header names or values (like
Authorizationorapplication/json) - Request and response bodies — any text content in the body (JSON fields, HTML content, error messages). Binary content (images, compressed data) is not indexed.
- Notes — your annotations on flows are searchable too
- Tags — both user tags and system tags are included in the search index
Search is exposed in two ways:
- The search bar at the top of the traffic view — type any text, or use the Ghost Query Language (GQL) for structured queries
- The AI agent’s
search_traffictool — the agent can search your traffic programmatically when analyzing flows or generating reports
Performance: Summary vs. Detail
Section titled “Performance: Summary vs. Detail”When you have 10,000+ flows in a session, loading every header and body for every flow would be extremely slow and consume too much memory. Ghost solves this with a two-tier loading strategy:
| What Loads | What’s Included | When It’s Used |
|---|---|---|
| Flow Summary (lightweight) | ID, method, URL, hostname, path, status code, duration, size, tags, source, timestamp — everything needed to display a row in the flow list | Always loaded for all flows in the current session. This is what powers the fast, scrollable traffic list. |
| Flow Detail (full data) | Everything from the summary PLUS all request/response headers, full request/response bodies, detailed timing breakdowns, metadata, and correlated interactions | Loaded on-demand when you click a specific flow to inspect it. Only one flow’s full data is in memory at a time. |
This means the flow list stays fast and responsive even with tens of thousands of flows, because it only holds lightweight summaries in memory. When you click a flow, Ghost fetches the full detail from the database in milliseconds. The virtual scrolling system (which only renders the ~30-40 rows visible on screen, not all 10,000+) works together with this summary approach to keep the UI snappy.