Skip to content

Inspect traffic

Body viewers

View bodies in Cloak Proxy as a JSON tree, pretty text, raw or hex. Query JSON with JSONPath or jq, and decode Protobuf, gRPC and MessagePack.

The Body tab of the inspector picks a viewer based on what the body contains. JSON opens as a searchable tree, images and web pages as previews, forms as tables, and binary data as a hex dump. Compressed bodies are decompressed first, and Protobuf, gRPC and MessagePack are decoded into JSON. The same viewer is used for request bodies, response bodies and WebSocket messages.

A JSON response in the tree view.

  1. Choose a view
  2. Content type and size
  3. Copy or save the body
  4. Filter keys and values
  5. Run a JSONPath or jq query
A JSON response body in the Tree view: a Key, Value and Type outline of two user objects, with the Tree, Pretty, Raw and Hex buttons, a filter field and tree tools above it

The buttons at the top left of the body switch between views. Which views you get depends on the kind of body, and the first one is the default.

Body Detected when Views
JSON The Content-Type contains json, or the body starts with { or [ and parses as JSON Tree, Pretty, Raw, Hex
gRPC The Content-Type contains grpc and the body decodes Tree, Pretty, Raw, Hex
Protobuf The Content-Type contains protobuf or x-proto and the body decodes Tree, Pretty, Raw, Hex
MessagePack The Content-Type contains msgpack and the body decodes Tree, Pretty, Raw, Hex
Image The Content-Type starts with image/ and macOS can open it Preview, Hex
HTML The Content-Type contains text/html Preview, Pretty, Raw, Hex
Form The Content-Type contains x-www-form-urlencoded Table, Raw, Hex
Text The start of the body is valid UTF-8, or the type is text/*, XML or JavaScript Raw, Hex
Binary Anything else Hex, Raw

Cloak Proxy remembers your choice for each kind of body. Pick Pretty for JSON once, and every JSON body opens in Pretty until you change it, while HTML keeps its own choice.

Item What it does
View buttons Switch between the views above
Truncated (orange) The body was larger than the capture limit, so only its first part was kept. It was still forwarded to the app in full.
Decoder note Says how a binary body was decoded, for example Protobuf decoded without a schema: fields are shown by number
Type and size The short content type and the body size, for example JSON · 429 bytes
Copy or save menu Copy Body copies the body as text. Save Body As… saves the decompressed body to a file, named after the last part of the URL.

A request or response without a body shows No body.

The Tree view shows JSON as an outline with three columns: Key, Value and Type. Array items appear as [0], [1] and so on. Objects and arrays show a summary such as { 8 keys } or [ 2 items ].

Values are colored by type: strings green, numbers blue, true and false orange, and null gray. Long strings are shortened in the cell and line breaks show as ⏎. Hover a value to see all of it.

Small documents (under about 400 values) open fully expanded. Larger ones open two levels deep. Double-click an object or array to open or close it.

Control What it does
Filter keys and values Shows only rows whose key or value contains your text (ignoring case), plus the objects and arrays that contain them. Matches are highlighted in yellow.
Expand all Opens every level
Collapse all Closes every level
Expand to a level Expand to Level 1 through Expand to Level 5
Sort keys Sorts object keys alphabetically. Also applies to copied JSON. Remembered.
Type column Shows or hides the Type column. On by default. Remembered.
Query Shows the query bar for JSONPath and jq
Copy menu Copy Pretty JSON, Copy Minified JSON and Copy Original Text (the body exactly as received, after decompression)

When a query result is showing, Copy Pretty JSON and Copy Minified JSON copy the result.

Item Appears for Copies or does
Copy Key Every row The key name, or the array index
Copy Value Every row Strings without quotes; objects and arrays as formatted JSON
Copy JSONPath Every row The row’s path, for example $.data.items[0].name. Keys with spaces or symbols are quoted: $['first name'].
Copy as Pretty JSON Objects and arrays The subtree, indented
Copy as Minified JSON Objects and arrays The subtree on one line
Expand Children Objects and arrays Opens everything inside the row
Collapse Children Objects and arrays Closes everything inside the row
Filter by “key” Object keys Puts the key in the filter field, so you see every place it appears

JSONPath picks values out of a large document by path, for example every product name over a certain price.

  1. In the Tree view, click Query.

  2. Choose JSONPath in the menu at the left of the query bar.

  3. Type an expression, such as $.data.items[?(@.price > 10)].name.

  4. Press Return or click Run.

    The tree shows the matches as an array, and the bar shows the count, such as 2 matches. A mistake shows an error in red with its position, such as Expected ‘]’ (at position 14).

  5. Click Clear to go back to the full document.

The query bar remembers the language you chose. Selecting another request clears the result.

Syntax Selects Example
$ The whole document. Optional: data.items works too. $
.key A key of an object $.data.owner
['key'] A key with spaces or symbols, in single or double quotes $['first name']
['a','b'] Several keys $.data.owner['name','email']
[n] An array item. Negative numbers count from the end. $.data.items[-1]
[n,m] Several items $.data.items[0,2]
[start:end:step] A slice. Any part can be left out. $.data.items[0:2]
[*] or .* Every item or value $.data.items[*].name
..key The key at any depth $..email
..* Everything at any depth $.data..*
[?(…)] Items that pass a filter $.data.items[?(@.price < 10)]

Inside a filter, @ is the current item.

Filter Meaning
@.price > 10 Compare with ==, !=, <, <=, > or >=. Numbers compare as numbers, text as text.
@.name == 'Lamp' Text in single or double quotes
@.name =~ /^L/ Matches a regular expression (also written as a quoted string)
@.tags The key exists
!@.tags The key doesn’t exist
@.price > 5 && @.price < 50 Both must be true. Use || for either, and parentheses to group.
@.active == true Also false and null
@.tags[0] == 'home' Paths can include indexes and quoted keys

Given this response:

Response body
{
"data": {
"items": [
{ "id": 1, "name": "Mug", "price": 12, "tags": ["kitchen"] },
{ "id": 2, "name": "Lamp", "price": 40, "tags": ["home", "sale"] },
{ "id": 3, "name": "Pen", "price": 3 }
],
"owner": { "name": "Ada Park", "email": "ada@example.com" }
}
}
Expression Result
$.data.items[0].name ["Mug"]
$.data.items[-1].name ["Pen"]
$.data.items[*].name ["Mug", "Lamp", "Pen"]
$.data.items[0:2].id [1, 2]
$..name ["Mug", "Lamp", "Pen", "Ada Park"]
$.data.items[?(@.price > 10)].name ["Mug", "Lamp"]
$.data.items[?(@.tags)].id [1, 2]
$.data.items[?(@.name =~ /^L/)].price [40]
$.data.owner['name','email'] ["Ada Park", "ada@example.com"]

jq is a command-line JSON processor with its own language for filtering and reshaping JSON. Cloak Proxy runs the jq installed on your Mac.

  1. In the Tree view, click Query.

  2. Choose jq in the menu at the left of the query bar.

  3. Type a filter, such as .data.items[] | select(.price > 10) | .name.

  4. Press Return or click Run.

    When jq returns one value, the tree shows it. When it returns several, they’re shown as an array.

Filter Result for the example above
.data.items | length 3
.data.items[] | select(.price > 10) | .name "Mug" and "Lamp", shown as an array
[.data.items[] | {name, price}] An array of objects with only name and price
.data.items | map(.price) | add 55

For JSON, Pretty re-indents the document with two spaces and colors it: keys purple, strings green, numbers blue, true and false orange, null gray. Key order is kept as received. Coloring is skipped for very large documents (around 3 MB and up). For HTML, it shows the markup as text.

Pretty JSON, indented and colored.

A JSON response in the Pretty view: an indented array of two user objects with colored keys and values

All three are selectable text. Press ⌘ F inside them to open a find bar, and right-click a selection to decode it with Quick Preview.

Preview renders an HTML body as a web page, so you can see what the server sent without opening a browser. JavaScript is turned off. Relative links resolve against the request’s URL, so the page can load its own images and stylesheets.

HTML bodies open in Preview. Switch to Raw for the markup.

  1. Preview, Pretty, Raw and Hex for HTML
An HTML response body with the Preview, Pretty, Raw and Hex buttons and the label HTML · 151 bytes

Preview shows the image at its own size, or smaller to fit, on a checkerboard so transparent areas are visible. The caption underneath gives its pixel size and file size, such as 120 × 80 · 10 KB. Any image format macOS can open works.

An image response with its dimensions.

  1. Pixel size and file size
A PNG response shown in Preview, with the caption 120 × 80 · 10 KB

URL-encoded form bodies (application/x-www-form-urlencoded) open as a Table of names and decoded values. + becomes a space and percent-encoding is decoded. Raw shows the original name=value&… text.

For requests, the Form tab in the inspector shows the same table, and also handles multipart/form-data uploads:

  • Text parts show their name and value.
  • File parts show their name, then a paperclip, the file name and its size, instead of the file’s bytes.
  • A part without a name is listed as part.

A multipart upload: one text field and one file.

The Form tab for a multipart upload: title Vacation, and photo shown as a paperclip with beach.jpg (8 bytes)

To get at a file inside a multipart body, use Save Body As… on the Body tab and extract it from the saved body.

Cloak Proxy decodes Protocol Buffers without a schema. The result opens in the Tree view with the note Protobuf decoded without a schema: fields are shown by number.

Protobuf fields appear under their field numbers.

  1. How the body was decoded
A Protobuf response in the Tree view with numbered fields: 1 is 150, 2 is the string testing, 3 is a nested message, 4 is an array of 1 and 2
In the message In the tree
Field number The key, such as 1 or 4
A field that repeats An array of its values
Varint A whole number (unsigned)
Fixed 32-bit or 64-bit A decimal number when the bits look like one, otherwise a whole number
Length-delimited, readable as text A string
Length-delimited, a valid message A nested object
Other bytes A string starting with base64:

Without the .proto file, Cloak Proxy can’t know field names or tell signed from unsigned numbers, so read numbers with that in mind.

gRPC bodies (a Content-Type containing grpc) are split into their length-prefixed messages first, with the note gRPC decoded without a schema: fields are shown by number. One message opens as an object; several open as an array. Compressed gRPC messages can’t be decoded and show as <compressed gRPC message, N bytes>.

MessagePack bodies (a Content-Type containing msgpack) are converted to JSON and open in the Tree view with the note MessagePack shown as JSON. Binary values show as base64: strings, the standard 32-bit timestamp extension shows as an ISO 8601 date, and other extensions show as an object with extType and data.

Cloak Proxy reads the Content-Encoding header and decompresses the body before showing it:

Content-Encoding Supported
gzip, x-gzip Yes
deflate (zlib-wrapped or raw) Yes
br (Brotli) Yes
identity or none Shown as is
Anything else Shown as received

If decompression fails, you see the bytes as they arrived. The decompressed body is what you see in every view, in the filters, and in Copy Body, Copy Request and Copy Response. Save Body As… saves the decompressed bytes too.

Limit Value
Body kept for inspection 32 MB by default. Change it with Max captured body size in Settings › General (see Network settings).
JSON tree Bodies up to about 30 MB. Larger JSON opens as text.
Raw and Pretty text The first 5 MB
Hex The first 256 KB
Filter body search The first 2 MB