Skip to content

2 · Analyzing the HAR in Postman

You've captured a HAR and imported it into Postman as a collection. Now find the one request that carries the customer's data and read its body. Everything you build next — the Custom Data Type and the Application — comes from this request.

Rather not leave the browser? You can import the HAR back into Chrome/Firefox DevTools and do the same thing — see the next page. Postman is the recommended path and what this chapter uses.


HAR structure in 30 seconds

Each HAR entry is one request/response pair. The fields that matter:

entry
├── request
│   ├── method       → Application method (GET/POST/…)
│   ├── url          → Application URL regex
│   └── postData
│       └── text     → THE REQUEST BODY (what you send)
└── response
    └── content
        └── text     → THE RESPONSE BODY (what you receive)

Postman maps this cleanly: each HAR entry becomes a request in the collection; its Body tab shows request.postData, and sending it shows the response.

The two bodies you'll live in:

  • Request body (request.postData.text) — what the browser sends. Source for request-side policies (blocking or detecting data on its way out).
  • Response body (response.content.text) — what the browser receives. Source for response-side policies (masking data on its way in to the user).

The direction the data lives in decides the Rule's Apply To later — note it now.


Step 1 — Find the request

In the imported collection:

  1. Scan the request list. Postman shows method + name/URL per request. The one you want is almost always Fetch/XHR: a POST/PUT/PATCH (for sends) or a GET returning JSON (for lists you want to mask).
  2. Search (the collection search box) for a literal you know is in the data — the email you typed, the amount, an ID. That jumps you straight to the carrying request.
  3. For GraphQL, open the Body tab — the operationName (e.g. ApplyDiscount) names the operation directly. All GraphQL goes to the same /graphql URL, so the body is how you tell operations apart.
  4. Ignore noise — analytics/telemetry hosts (segment, datadog, sentry, google-analytics), images, fonts, CSS. A clean single-action capture leaves only a handful of real candidates.

Confirm by re-firing

Click Send on the candidate request. If it reproduces the action (or returns the data you expected), you've got the right one. You can tweak a body value and re-send to confirm which field drives the behavior.


Step 2 — Read and pretty-print the body

Open the request's Body tab (for sends) or Send it and read the Response body (for receives). Use Postman's Pretty view to format the JSON. You'll see something like:

{
  "action": "ApplyDiscount",
  "record": {
    "opportunityId": "0065g00000ABCDE",
    "discount": { "amount": 17, "currency": "USD" }
  }
}

Response sometimes arrives encoded/compressed

If a response body looks like gibberish or base64, it was compressed/encoded on the wire. Re-firing in Postman decodes it for you (Postman handles gzip), which is one more reason to use it for response-side analysis.


Step 3 — Read the shape (this is the data type)

Look at the body as a tree and answer three questions:

  1. What uniquely identifies this request among others to the same URL? For REST it might be an action field, a type field, or simply the URL path. For GraphQL it's operationName. → becomes the condition / anchor of your Data Type.
  2. Where exactly does the value live? Walk the key path: record.discount.amount, results[].properties.email, messages[].content.parts[]. → becomes the traversal.
  3. Is it a single value, a value inside a repeated object, or an array of values? Single → plain Object traversal. Repeated (a list of users, a list of messages) → you'll need an Array step. → decides whether your DSL needs an Array node.

Write the path in plain English first:

"In the ApplyDiscount request, the discount is at record.discount.amount."

"In the contact-list response, every element of results[] with type == "contact" has the email at properties.email."

That sentence translates almost mechanically into the Search DSL in Custom Data Types.


Step 4 — Note the URL and method

From the request's URL bar, record:

  • the full URL (https://acme.my.salesforce.com/services/apexrest/discount) — for the Application match, and
  • the method (POST) — to constrain the Application.

That's everything the Applications chapter needs.


What Shield can (and can't) match

Shield scans bodies, by content type. It does not scan request/response headers for data values (headers are only used for routing/identity filters). Supported body types:

Content type Matched? Notes
application/json (++json) Includes GraphQL — it's just JSON. Use the JSON DSL.
text/plain Regex matchers
text/html XPath + regex
application/xml, text/xml (++xml) XPath + regex
text/csv Column-name + cell regex
application/x-www-form-urlencoded Parsed into key/value pairs
multipart/form-data Each part scanned by its own content type
text/event-stream (SSE) Streamed AI responses — scanned line by line
Office Open XML / PDF Text extracted, then regex
Request/response headers Used for routing/identity only, not value detection

Most custom policies are JSON (REST APIs and GraphQL), which is why the Custom Data Types chapter focuses on the JSON Search DSL. Check the Content-Type (Postman shows it on the request/response Headers tab) to know which matcher family you're in.


Next: Analyzing the HAR in the browser → (alternative), or skip straight to Custom Data Types →.