Tidyleaf

How to read conversations.json (ChatGPT and Claude data export)

conversations.json is the file that holds your chat history when you request your data from ChatGPT or Claude. It is not meant for reading: it is one long line of JSON, and in ChatGPT’s version the messages are stored as a tree, not a list. This guide covers how to request the export, what is inside the zip, how the structure works, and four ways to turn it into files you can read.

The short route: drop the zip or the JSON into our free converter. It runs in your browser, uploads nothing, and gives you Markdown, Word or HTML files, one per conversation. The rest of this page is for when you want to understand the file or do it yourself.

1. Request your export

ChatGPT

OpenAI’s help article gives two routes. The one most people want is in settings:

  1. Sign in to chatgpt.com (the export is not available while logged out).
  2. Open your profile menu and choose Settings, then Data controls.
  3. Under Export data, select Export, then Confirm export.
  4. Wait for the email or SMS. OpenAI says exports can take up to 7 days to arrive. Select Download data export in the message. The link expires 24 hours after you receive it, and you should be signed in to the account that requested it.

The other route is OpenAI’s Privacy Portal: Make a Privacy Request, I have a consumer ChatGPT account, Download my data.

Self-service export is available for ChatGPT Free, Go, Plus, Pro and eligible Edu workspaces. It is not available in Business, Enterprise or ChatGPT for Healthcare workspaces; ask your workspace owner. If you plan to move a personal workspace into a managed one, export first, because after the personal workspace is removed you may no longer be able to request another export.

Claude

Anthropic’s help article says:

  1. On claude.ai or Claude Desktop, click your initials in the lower-left corner and choose Settings.
  2. Open Privacy and click Export data.
  3. Anthropic emails a link to your account address after a short processing delay. You must be signed in to download, and the link expires 24 hours after delivery.

The iOS and Android apps cannot start an export. Free, Pro and Max users export their own data; on Team and Enterprise plans only the organization’s Primary Owner can. Exports cannot be imported into another personal Claude account.

2. What is in the zip

OpenAI and Anthropic do not publish a specification for these files, so what follows comes from real exports and community write-ups, and either company can change it. Check your own zip.

ChatGPT zips typically contain:

Claude zips typically contain conversations.json, projects.json and users.json.

3. The structure of ChatGPT’s conversations.json

The file is a JSON array. Each element is one conversation with fields such as:

{
  "title": "Sorting dicts in Python",
  "create_time": 1760000000.0,
  "update_time": 1760000300.0,
  "current_node": "a_new",
  "mapping": { "...": "..." }
}

(create_time is a Unix timestamp in seconds.)

The mapping tree

mapping is an object keyed by node ID. Each node looks like this (trimmed):

"u_new": {
  "id": "u_new",
  "parent": "sys",
  "children": ["a_new"],
  "message": {
    "author": { "role": "user" },
    "create_time": 1760000100.0,
    "content": { "content_type": "text", "parts": ["How do I sort a list of dicts by key?"] },
    "metadata": {}
  }
}

Why branches exist

ChatGPT never deletes a message when you edit a prompt or press regenerate. The new version becomes a second child of the same parent node, and the old version stays in the tree. So a node can have two or more children, and mapping holds every draft you ever made, not just the chat you remember.

current_node is the ID of the last message on the branch that was on screen when the export was made. To rebuild the visible thread, start at current_node, follow parent up to the root, and reverse the list. Reading mapping in dictionary order, or taking every message, mixes old drafts into the conversation.

Claude’s format is flatter

Claude’s conversations.json is also an array. Each conversation has uuid, name, created_at, updated_at and a chat_messages list. Each message has a sender (human or assistant), a created_at, and its text either in a text field or as typed blocks in a content list. Attachments appear under attachments (with extracted text) and files, and artifacts appear as tool-use blocks. There is no tree to walk. Edited-message branches are not represented the way ChatGPT’s are, so you generally see one linear thread.

4. Four ways to make it readable

A. Tidyleaf converter (no install, nothing uploaded)

Open the converter, choose the zip or the JSON, search your conversations, tick the ones you want and download .md, .docx or .html files, a zip of them, or one combined Markdown file. It follows current_node, so you get the branch you saw, and it keeps code blocks with their language, tables and lists. Hidden system messages and tool output are skipped, and images and attachments become placeholders such as [Image attachment]. It streams the file, so a 100 MB or larger export does not freeze the page. Disclosure: Tidyleaf is us. The tool is free and independent of OpenAI and Anthropic.

B. A short Python script (ChatGPT)

This script needs only Python 3. Put it next to your unzipped conversations*.json files and run it. It writes one Markdown file per conversation into a chats folder, following the active branch.

import glob, json, pathlib, re

out = pathlib.Path("chats")
out.mkdir(exist_ok=True)

for path in sorted(glob.glob("conversations*.json")):
    for conv in json.load(open(path, encoding="utf-8")):
        # Walk from the last node of the visible branch up to the root.
        chain, node_id = [], conv.get("current_node")
        while node_id:
            node = conv["mapping"][node_id]
            chain.append(node)
            node_id = node.get("parent")

        blocks = []
        for node in reversed(chain):
            msg = node.get("message")
            if not msg or msg["author"]["role"] not in ("user", "assistant"):
                continue
            if (msg.get("metadata") or {}).get("is_visually_hidden_from_conversation"):
                continue
            parts = (msg.get("content") or {}).get("parts") or []
            text = "\n".join(p for p in parts if isinstance(p, str)).strip()
            if text:
                blocks.append(f"## {msg['author']['role'].title()}\n\n{text}\n")

        title = conv.get("title") or "Untitled"
        name = re.sub(r'[\\/:*?"<>|]+', "-", title).strip()[:80] or "Untitled"
        (out / f"{name}.md").write_text(f"# {title}\n\n" + "\n".join(blocks), encoding="utf-8")

Known limits: it keeps only plain text parts, so images, code-interpreter output and reasoning summaries are dropped; ChatGPT citation markers can survive as odd private-use characters in the text; and two chats with the same title overwrite each other, so add the conversation’s ID or date to the file name if that matters. For very large files, json.load needs memory of several times the file size; the third-party ijson package can stream the array instead.

C. jq for a quick look

To list titles and dates without writing a script, with jq: jq -r '.[] | [.create_time, .title] | @tsv' conversations.json. For Claude, use .created_at and .name. jq reads the whole file into memory, so use --stream or a script for multi-gigabyte exports.

D. chat.html or an extension

chat.html in the ChatGPT zip opens in any browser and is fine for scrolling a recent chat, but it is one page for everything and cannot be searched per chat or saved as separate files. If you only need a chat you have open right now, you do not need the data export at all: our free AI Chat Exporter extension saves the open ChatGPT, Claude or Gemini conversation as Markdown or PDF in one click (bulk export of every chat is a paid Pro feature; the converter above is free).

5. Common problems

FAQ

Where is conversations.json after I export my ChatGPT data? In the zip that ChatGPT emails you after you choose Settings, Data controls, Export data. Unzip it and you find conversations.json (large accounts may have several numbered files such as conversations-000.json) next to other files, and often a chat.html page. Claude’s export zip also contains a conversations.json.

How long does the ChatGPT export take, and when does the link expire? OpenAI’s help page says an export can take up to 7 days to arrive and that the download link expires 24 hours after you receive it. Claude’s help page says its link also expires 24 hours after delivery.

Why is conversations.json one huge line and hard to open? The export is compact JSON with no line breaks, and for heavy users it can run to hundreds of megabytes, which text editors struggle with. Use a streaming reader, a script, or a converter that parses it for you.

Why does a ChatGPT conversation contain a mapping instead of a list of messages? Because ChatGPT conversations are trees. Editing a message or regenerating a reply creates a new branch, and the old branch is kept. Each node points to its parent and children, and current_node marks the end of the branch that was on screen.

How do I know which branch I was actually looking at? Start at the conversation’s current_node and follow each node’s parent up to the root, then reverse the list. That path is the thread as it appeared in the app. Other branches in the mapping are older edits or regenerated replies.

Is my data safe if I use an online converter? Only if the converter works locally. Tidyleaf’s converter reads the file in your browser, makes no request carrying your data and has no server, and you can confirm that in your browser’s Network tab. Treat any converter that uploads the file as a transfer of your whole chat history.

Can I import conversations.json into another chat service? Claude’s help page says exported data cannot be imported into another personal Claude account. For reading or searching, convert the file to Markdown or Word. Converting does not recreate chats inside ChatGPT or Claude.

Does the export contain my images, voice chats and canvas documents? Not reliably. Text conversations are in conversations.json, with images and files referenced rather than embedded as readable text. Reasoning summaries, search results, canvas and similar content types have different shapes, and simple scripts often skip them. Tidyleaf’s converter turns images and attachments into placeholders.

Tidyleaf is an independent maker of browser extensions. Not affiliated with, endorsed by or sponsored by OpenAI or Anthropic. ChatGPT and Claude are trademarks of their owners, named only to describe the files this guide explains.