File Format (.pro)
A .pro file is a JSON-encoded snapshot of captured traffic. Probe writes one when you export: a saved session from View → Sessions → Export, or requests from a row's or a selection's Export menu. Saving a session stores it in Probe's local database (~/.probe/probe.db), not as a file. Earlier versions of Probe saved the same file shape as .gmp; both extensions are still accepted on import.
Probe also writes two related shapes — collection exports for a multi-entry export and request exports for a single entry. The importer routes by the JSON format field, not the file extension.
Top-level shape
Section titled “Top-level shape”The first key tells the importer what's inside:
{ "format": "guide-session" | "guide-collection" | "guide-request", "version": 1, ...}Probe trusts the format value over the extension — you can rename a file from .json to .pro (or vice-versa) and import will still work.
guide-session
Section titled “guide-session”The full snapshot a saved tab produces. Saved sessions themselves live in Probe's local database (~/.probe/probe.db); this JSON is the interchange shape that Export writes to a path you choose and Import reads back.
{ "format": "guide-session", "version": 1, "id": "1731081900123", "name": "Auth flow — staging", "createdAt": 1731081900123, "entries": [ { /* LogEntry */ }, { /* LogEntry */ } ]}| Field | Type | Description |
|---|---|---|
format | string | Must be "guide-session". |
version | integer | 1 today. Bumped on a breaking format change. |
id | string | Session id: the save time in milliseconds, as a string. Two sessions saved in the same millisecond get a _1-style suffix. |
name | string | Display name. Editable via the Sessions manager. |
createdAt | integer | Milliseconds since epoch, UTC. |
entries | array | One LogEntry per captured request. |
guide-collection
Section titled “guide-collection”The export format for a multi-entry export (right-click on selected rows → Export).
{ "format": "guide-collection", "version": 1, "exportedAt": 1731082000000, "entries": [ /* LogEntry, ... */ ]}Same entries shape as a session, without the session-level id and name. On import, the entries are added to the session tab you have open — or, when that's a saved (read-only) tab, to the recording tab — and Probe switches to that tab, even from a Composer or Files tab. The tab gets the unsaved marker, so save it to keep the import.
guide-request
Section titled “guide-request”A single-entry export. Useful for sharing one request without surrounding noise. It imports like a one-entry collection.
{ "format": "guide-request", "version": 1, "entry": { /* LogEntry */ }}LogEntry shape
Section titled “LogEntry shape”The same LogEntry JSON appears inside every format above:
{ "id": 142, "method": "POST", "url": "https://api.example.com/v1/users", "statusCode": 201, "timestamp": 1731081900123, "clientAddr": "Chrome", "reqHeaders": { "content-type": "application/json", "authorization": "Bearer ..." }, "reqBody": "{\"name\":\"Ada\"}", "resHeaders": { "content-type": "application/json", "content-length": "21" }, "resBody": "{\"id\":1,\"name\":\"Ada\"}", "contentType": "application/json", "durationMs": 184, "reqSize": 124, "resSize": 21, "requestEndTs": 1731081900140, "responseStartTs": 1731081900290, "httpVersion": "HTTP/1.1"}| Field | Type | Notes |
|---|---|---|
id | integer | Unique per session. Imported request and collection entries get new ids (negative numbers, shown as #-1, #-2, …) so they never collide with traffic captured live. |
method | string | HTTP method. |
url | string | Full URL the client sent. MITM-intercepted entries carry the explicit :443/:80 port. |
statusCode | integer | 0 if no response was received (request errored mid-flight or was aborted). |
timestamp | integer | Milliseconds since epoch, UTC. |
clientAddr | string | Process name for loopback traffic, IP address for remote phones. May be empty. |
reqHeaders | object | Lower-cased keys, single value per key. |
reqBody | string | null | Raw body as text. A non-text or oversized body is replaced by a short placeholder in square brackets, such as [binary 2048 bytes] or [body too large: 12582912 bytes, not shown]. |
resHeaders | object | Same conventions as reqHeaders. |
resBody | string | null | Same conventions as reqBody. |
contentType | string | null | Sniffed from the response. |
durationMs | integer | null | Total request → response time. |
reqSize | integer | Bytes-on-the-wire estimate of the request. |
resSize | integer | Bytes-on-the-wire estimate of the response. |
requestEndTs | integer | null | Milliseconds since epoch, UTC, when Probe had the whole request body. Missing in files from older versions. |
responseStartTs | integer | null | Milliseconds since epoch, UTC, when the first response byte arrived. Missing in files from older versions. |
httpVersion | string | Protocol version, such as HTTP/1.1 or HTTP/2.0. Empty when unknown. |
Only id, method, url and timestamp are required. Other fields may be missing — LogEntry.fromJson fills in defaults (statusCode 0, no headers, sizes 0) — and fields it doesn't know are ignored, so a file from a newer version of Probe still loads in an older one.
Compatibility
Section titled “Compatibility”.gmpfiles — same JSON shape, accepted by every importer. Probe writes.profor new exports..jsonfiles — accepted; the importer sniffsformat.- Renamed extensions — fine. Content-sniffing wins over the extension.
What's NOT in the file
Section titled “What's NOT in the file”- No request/response that was already discarded for size — bodies stripped at capture time stay stripped. Sessions are wire-level, not browser-level.
- No HAR support today. Probe doesn't read or write HAR.
- No environment data, scripts, breakpoints, or rules. A
.proonly carries traffic. Compose collections (with environments and scripts) live separately under~/.probe/compose/<collection-id>.json.
See also
Section titled “See also”- Sessions — the user-facing feature this format underpins.
- Internal REST API — fetch saved sessions via
/api/v1/session-tabs/saved/{id}.