ChatGPT Retrieval Dissector

Paste the SSE stream of a ChatGPT conversation request and see every web.run retrieval call in order, the queries it disclosed, the results it forwarded, the sources panel, the citations and the model's thoughts. Every item links back to its line in the stream.

Open the browser's developer tools (Network tab) while ChatGPT answers, find the POST …/backend-api/f/conversation request and copy its response body — the event: delta / data: {...} stream. Paste it below.

Nothing leaves the browser. The text is parsed in a Web Worker on this page. There is no upload, no server and no external request. Session tokens and your custom instructions are masked before anything is shown.

Checked against the wire queries: exact, near (case, quotes, spaces) or unverified; unverified ones are attributed to the calls that disclosed nothing.

Report

Raw stream

read-only, masked, verbatim otherwise · click any L-number above to jump here

How it reads the stream

  • Each data: line is a full message ({"v":{"message":…}}) or a patch. Patches are applied to the message whose channel number c matches; patches without c go to the most recently added message. A bare {"v":"text"} repeats the previous text append on that message (the answer streams this way), so answer text and the citations inside it are complete.
  • A retrieval call is an assistant message with recipient web.run. Calls are ordered by the parent_id chain, not by file position or create_time.
  • A call whose message carries inline_cot_expandable_content ran inside the chain of thought (the "Searched N websites" box); its queries are hidden by design. A call without it is a visible call, and the UI shows its queries. The report labels every call and every citation with its block.
  • Disclosed queries come from the web.run tool message that carries metadata.search_model_queries.queries and points at the call through parent_id. A visible call without one is flagged.
  • Results are metadata.search_result_groups[].entries[]. Groups accumulate, so a call owns the entries whose turn_index first appears under it.
  • The content of inline_cot_expandable_content is the accumulating "Searched N websites" panel. It is kept as its own layer and never counted as tool results, so the report can show which forwarded entries the panel never surfaced, and which panel entries no tool message forwarded. Each call also lists the metadata keys of its call, query and result messages (reasoning titles, tool icons, group counts, thread ids), with boilerplate request keys hidden.
  • The sources panel is the set of groups with small turn_index (0, 1, …) on the final messages. Panel turn k is the k-th search call in chain order (view-only calls skipped; a search call that forwarded nothing still takes a slot), verified by URL overlap with what the tool message forwarded, with a fallback match by overlap when the ordinal fails. Merging both by ref_index gives a lower bound on the pool the model received: which slots only the tool message had, which only the panel had, which are still missing, and the pool size (max ref_index + 1). Neither slice is complete; the tool message tends to keep news hits and drop the tail, the panel drops news and keeps more of the tail, and whole site: sub-queries can vanish from one of them. A disclosed query with a site: operator is flagged when no merged entry is on that site.
  • What the reader never saw. ChatGPT shows retrieved sources in two places: the thinking panel ("Searched N websites", from inline_cot_expandable_content) and the Sources footnote under the answer (from the small-turn_index panel groups); inline citations are a third, narrower path. The tool message is not a surface. Every reconstructed pool slot is classified by which of these showed it. Slots in none of them, and index gaps that no copy carries, are retrieval the model had and the reader never could see. The section at the top of the report lists them with URLs where the stream has one, and offers a CSV.
  • Citations are <Cite refs={["turn{T}{type}{N}"]}/> tags in the answer text plus content_references[].refs, resolved by (turn_index, ref_type, ref_index). Message fragments that were merged into a final message are not double-counted.
  • Bad JSON lines, a truncated last line and missing fields become parse warnings; the report is still produced.