Skip to content

Network + Console · 6 minutes

Inspect network requests in Safari on iPhone and iPad

A loading spinner tells you that the page is waiting, but not what it is waiting for. Start with a request you can reproduce. Codable’s Safari extension can capture fetch and XMLHttpRequest activity in the tab you are already using, so you can compare the request, response and visible result without opening a separate browser session.

Before you start

Install Codable on iPhone or iPad running iOS or iPadOS 26.4 or later. Enable it in Settings → Apps → Safari → Extensions. Open the local demo from Codable’s Extension screen, allow the extension on that Safari page, then open Codable from Safari’s extensions menu. The demo requests stay on the local fixture server.

Codable on the App Store ↗
  1. Initialize Network before the action

    Choose Network and use Clear to empty the list. Opening this panel initializes detailed capture for subsequent fetch and XMLHttpRequest calls. Close the popover before interacting with the page.

    Resource-timing entries may already be present, but they cannot reconstruct an earlier request’s missing method, status, headers or body. After navigating or reloading, open Network again before reproducing the problem.

    Check: You have an empty list and a known starting point for the next demo request.

  2. Inspect a successful request

    In the demo’s Network section, tap Fetch products. Reopen Codable → Network, tap Refresh, and select the /api/products entry.

    Read the captured method, status, duration and available response preview. Compare the preview with what appeared on the page. Keep the request URL and the action that triggered it together; a long list of background requests is harder to interpret.

    Check: The local products request returns HTTP 200 and a JSON response that the demo displays.

  3. Compare an HTTP error with a rejected request

    Clear Network, close the popover, and tap Fetch error on the demo. Reopen Network, Refresh, and select /api/error. The local server intentionally returns HTTP 500 for this exercise.

    An HTTP error response is still a response. JavaScript fetch does not reject just because the status is 500; application code must check response.ok or the status. A rejected fetch can instead mean that the browser could not provide a response, for example because of a connection or access restriction. Preserve the observed status or error rather than treating those cases as interchangeable.

    Check: The /api/error entry has an HTTP 500 response, while the demo remains usable.

  4. Connect the observation to the symptom

    Open Console and reproduce the same demo action to compare its Fetched demo error message with the request. This message is explicitly logged by the demo; it is not a debugger pause or proof that an unrelated exception caused the request.

    On your own page, record the action, expected result, request status and available response detail. If the response is successful but the page stays empty, inspect the code that consumes it. If capture lacks a status or body, record that gap and gather more evidence instead of guessing a server error.

If you get stuck

The request is missing

Confirm permission for the current Safari page, open Network first, and repeat a safe action. Requests made before initialization, by workers, in inaccessible frames, or outside the instrumented page can be absent. An empty list does not establish that no request occurred.

The row has timing but no body

It may be a resource-timing observation rather than an instrumented fetch or XHR. Timing does not reveal an otherwise unavailable response body. Keep that distinction when describing the result.

Headers, status or response text are incomplete

Browser access rules and bounded capture can hide or truncate details. An unavailable field is unknown, not a successful value. Use the server’s own logs or desktop remote inspection when the missing detail is necessary.

What this can tell you

  • This is page-level instrumentation plus resource timing, not a recording of every browser HTTP transaction. Navigation requests, workers, caches and inaccessible frames can have different coverage.
  • A response preview is bounded and may not contain the complete body. Browser restrictions also limit exposed headers and cross-origin timing details.
  • The extension inspects the current Safari page. Resize and Scratchpad use separate browser contexts and do not inherit its authenticated state.
  • URLs, headers and response content can contain private information. Review the details before copying them into an issue or a chat, and omit credentials or personal data.

For a full debugger connected to a Mac, Apple documents remote inspection of iOS and iPadOS. For extension setup, see Apple’s Safari extensions guide.