Chat Thread Viewer
Paste an OpenAI or Anthropic messages array (JSON) and see it rendered as a readable chat thread. Color-coded by role. Tool-call params expanded. Pure browser, no upload.
Visualising API message arrays
LLM applications log their conversations as JSON arrays of messages — that's what gets sent to the API and what you'll see in audit logs, evaluation traces, fine-tuning datasets, and SDK debug output. Reading those arrays as a human is awful: walls of escaped strings, tool-call arguments wrapped in escaped JSON-inside-JSON, system prompts mashed in with the rest of the flow. This tool gives you a quick chat-bubble render so you can scan the actual conversation, see which messages contained tool calls, and spot the one prompt that went sideways.
Supported conversation formats
- OpenAI Chat Completions.
[{role, content}, ...]with optionaltool_callson assistant messages androle: "tool"for tool results. The most common shape. - Anthropic Messages API.
[{role, content: [...]}]wherecontentis an array of blocks (text,tool_use,tool_result,image). System prompt is usually top-level — paste it as a system message if you want it shown. - LangChain message dumps.
[{type: "human" | "ai" | "system", content: ...}]— older LangChain shape, still common in saved traces. - Wrapper objects. If you paste
{"messages": [...]}or{"input": [...]}, the wrapper gets unwrapped automatically.
Bubbles, tool calls, code fences, and stats
- Role-coloured bubbles. System = grey centred, user = indigo right-aligned, assistant = neutral left-aligned, tool result = green.
- Tool calls. Expanded by default with pretty-printed arguments. Both OpenAI's
tool_callsform and Anthropic'stool_useblock style are handled. Tool result messages render as a separate bubble with the result content. - Code fences and inline code. Triple-backtick blocks render as
<pre>with monospace, single-backtick spans render as inline code. No syntax highlighting (we don't ship a tokenizer for that), but indentation is preserved. - Image references. Anthropic image blocks render a small pill showing the source URL or media type — we don't actually load the image (keeps the tool offline).
- Stats line. Format detected, message count, tool-call count, and a rough token estimate using the same heuristic as our Token Counter (chars / 3.8 for English, 1 token per CJK char).
Escaped JSON, missing system prompts, and trailing commas
- Trailing commas. Standard JSON doesn't allow them. If you copied from a debugger or REPL output, you may need to clean up
{...},]→{...}]before pasting. - Single quotes. Python's
repruses single quotes. Run it throughjson.dumpsbefore pasting, or use a Python-literal-to-JSON converter. - Anthropic system prompt. The system instruction in Anthropic's API is a top-level field, not a message. If your dump only has the messages array, the system prompt won't be in there — paste it as
{"role": "system", "content": "..."}at the start to see it. - Tool-call arguments as escaped JSON. OpenAI returns
argumentsas a string of JSON. We unescape and pretty-print it. If your JSON-in-string is malformed, the raw string is shown instead. - Privacy. Nothing leaves the page. The whole render runs in JS on whatever JSON you paste. Don't paste anything you wouldn't paste into a notepad app.
A sample parse
Paste an OpenAI [{role, content}, …] array with a couple of tool_calls on the assistant turns. The viewer renders it as chat bubbles, flags which turns carried tool calls, and unwraps the escaped JSON-inside-JSON arguments — so you can read what the model actually asked the tool to do instead of squinting at a wall of backslashes.
Formats, privacy, and tool-call rendering
Which log formats does it understand? OpenAI Chat Completions, the Anthropic Messages API content-block shape, and the older LangChain human/ai/system dumps still common in saved traces.
Is my conversation uploaded? No — it parses the JSON in your browser. Audit traces, prompts, and tool arguments stay on your machine.
Does it show tool calls and results? Yes — assistant tool_calls and tool/tool_result messages are rendered distinctly, with their escaped arguments unwrapped for reading.
What about images in the messages? Image blocks are recognised in the structure; the viewer focuses on the conversational flow rather than rendering the image bytes themselves.
Debugging long multi-turn threads
- Use the search bar to locate specific turns. In a 200-message eval trace, scrolling is painful. Type a function name, error string, or keyword into the search field and the viewer highlights every matching bubble — so you jump straight to the turn that matters.
- Watch the token estimate climb. The stats line shows a running token estimate for the entire thread. If a conversation blew past a context window, the estimate tells you roughly where the budget ran out — without running a real tokenizer.
- Tool-call chains are easier to follow here than in raw JSON. When the model calls a tool, gets a result, then calls another tool based on that result, the bubble layout makes the sequential logic visible. In raw JSON, tool-call IDs and tool-result references are just opaque strings buried in nested objects.
- Paste partial threads. You don't need the full conversation — paste any contiguous slice of the messages array and it renders correctly. Useful when you only have a log excerpt or want to focus on the last few turns.
- Content-array blocks render individually. Anthropic messages that contain multiple content blocks (text followed by tool_use, for example) render each block in sequence within the same bubble, so you see the model's reasoning alongside the tool call it triggered.
Exporting and sharing rendered threads
The rendered thread lives in your browser's DOM — use your browser's built-in screenshot or print-to-PDF to capture it. That's often the fastest way to attach a conversation excerpt to a bug report or share a prompt trace with a colleague who doesn't want to read raw JSON.