Capture one action before filtering the traffic

Pick a concrete question: which request loads a project list, changes a filter or opens a detail panel? Starting with a single action makes it easier to recognize the relevant response among fonts, images, analytics and background refreshes. Keep a note of the visible record or search term you expect to find.

  1. Open the website in Chrome. Open DevTools from the browser menu and choose Network.
  2. Check that recording is active, then reload. Requests made before the panel opened will not appear retroactively.
  3. Clear the displayed log to isolate the next action. Enable Preserve log if the workflow navigates to another page.
  4. Perform the action once. Start with Fetch/XHR to narrow ordinary data requests.
  5. Open likely requests and read their Response or Preview. Look for the record or text you just saw on screen.

Chrome’s network inspection tutorial explains the panel’s basic controls. An endpoint does not need /api/ in its path, and the data host may differ from the website’s domain.

Record the method, URL and inputs together

A URL alone is rarely enough to describe an operation. In Headers, inspect the request URL, HTTP method, response status and content type. In Payload, distinguish query-string parameters from a JSON body or form data. Read the response to check that this call actually carries the data you need.

Illustrative project search
GET https://api.example.com/projects?search=atlas&limit=20

200 application/json
{
  "items": [
    { "id": "project_7d8e9f01", "name": "Atlas" }
  ],
  "nextCursor": "cursor_81c2d903"
}

Here, /projects is the path, search and limit are inputs, and items holds the records. The cursor suggests another request may retrieve the next page. It does not prove that a parameter named page exists: use the interface’s next-page control and inspect what it actually sends.

Repeat with a different search term. A field that changes with your input is stronger evidence than a parameter that merely happened to be present. The Initiator tab can help locate the browser code responsible for a request; it does not show the server’s internal implementation.

Recognize different operations behind the same URL

If every useful call is a POST to /graphql, count the operations in the payload rather than counting distinct URLs. A GraphQL request may contain operationName, variables and query text, or a persisted-query hash in place of the text. One HTTP body may also contain a batch of operations.

JSON-RPC follows a similar pattern with a method and params inside its envelope. Ordinary JSON sent over HTTP is not automatically either protocol. Check the structure before deciding how to document the call.

For GraphQL, compare the selected fields in the response and use the schema reconstruction guide to understand what can be recovered. Recording only POST /graphql would hide the distinction between loading the project list and changing a project.

Why are there no useful Fetch/XHR requests?

An empty filtered list does not establish that the website has no API. Remove the filter and repeat the action while watching the full log. Chrome’s Network reference documents the request filters, payload views and stream inspection controls.

  • The data arrived with the page. Inspect the document response. A server-rendered screen may not fetch its initial data in a separate request.
  • The browser reused data. Try a different record or reload with Disable cache enabled while DevTools is open. Application memory and service-worker caches may still need separate investigation.
  • The feature uses a stream. Inspect WebSocket connections and their messages. For supported streamed HTTP responses, look for the EventStream tab. See WebSocket and SSE documentation.
  • The action opened another tab. Inspect that tab’s traffic. A log from the original page may not contain its requests.
  • The action did not reach the server. Client-side validation, a local filter or a disabled control may explain the absence.

Finally, check the body itself. An HTML sign-in screen or an access error is not the expected data response, even if the request URL looks plausible. Establish the normal signed-in workflow before inferring its data model.

Turn the observation into a reproducible request

Write down the trigger, method, host, path, input locations and a short response example. Identify which values came from the user and which came from an earlier response. An item identifier copied from today’s capture may work once while hiding a required lookup step.

Chrome can copy a request as cURL, which is useful for inspecting how the browser constructed it. Review the command before saving or sharing it: it may include authentication headers, cookies or personal data. Replaying an observed request can perform the same action again. Start with a read-only lookup when checking whether your interpretation is correct.

A request that fails outside the browser may depend on a current session, a token or a value produced earlier in the workflow. Compare those inputs before assuming the endpoint changed. The request-chaining guide explains how to trace a returned identifier into the call that consumes it.

Move from individual calls to an API inventory

Keep using DevTools when you need the raw details of one exchange. When the investigation spans many operations, apispy provides a persistent workspace organized by domain, inferred schemas, coverage observations and specification exports.

Open apispy’s analysis browser and repeat the workflow there. Its dedicated Chrome profile is separate from the window used in the steps above, so sign in again if needed. Select the relevant host, inspect Operations, then export an OpenAPI document. Review Coverage before treating a single successful response as representative.

This process discovers what the browser used. It cannot enumerate server-to-server calls or endpoints the interface never exercises. If your goal is a broader investigation of an undocumented application, continue with the API reverse engineering workflow.

Documentation by apispy. Product behavior described here reflects apispy v0.1. Inferred documentation depends on the traffic you observe.