Disclaimer: This is an experimental tool provided as-is, with no guarantees of correctness, reliability, or fitness for any purpose. It accesses ChatGPT's unofficial backend API, which may change or break at any time. By using this tool, you accept all responsibility for how you use it. I make no representations about the legality of exporting your own data in your jurisdiction, whether this use complies with OpenAI's Terms of Service, or any other legal or compliance matters. Use at your own risk.
Bulk export all your ChatGPT conversations using the backend API. Works with both personal and Teams accounts. Resumable — if your token expires mid-export, just run again with a fresh token and it picks up where it left off.
Supports:
- Regular conversations — your main ChatGPT history
- Project conversations — conversations inside ChatGPT Projects
- File downloads — DALL-E images, canvas documents, user uploads, attachments
- Deep research — captures async research task results
- Enhanced Markdown — browsing results, reasoning/thinking, tool usage
- Node.js 18+ (uses native
fetch)
Important: If you have multiple ChatGPT accounts, make sure you're only logged into the one you want to export. Being logged into more than one account at the same time can cause ChatGPT to return data from the wrong account.
- Open https://chatgpt.com in your browser and make sure you're logged in
- Open DevTools (F12) → Network tab
- Refresh the page or click on a conversation
- Filter requests:
backend-api/conversations - Click on a matching request, find the Authorization header under Request Headers, and copy the token (just the
eyJ...part afterBearer)
Warning: Bearer tokens can expire quickly — you may want to get a fresh one each time you run the export.
Setup:
npm installRun:
npx export-chatgptBy default, conversations are saved to ./exports/{user_id}:
exports/{user_id}
├── json/ # Regular conversation JSON
│ └── {date}_{title}_{id}.json
├── markdown/ # Regular conversation Markdown
│ └── {date}_{title}_{id}.md
├── files/ # Files from regular conversations
│ └── {file_id}.{ext}
├── projects/ # Project-scoped exports
│ ├── {ProjectName}/
│ │ ├── json/
│ │ ├── markdown/
│ │ └── files/
│ └── project-index.json
├── conversation-index.json
└── .export-progress.json # Resumption state
Files are named with the pattern {date}_{title}_{id}.{ext}.
The script tracks progress automatically:
exports/{user_id}/.export-progress.jsonstores which conversations have been downloaded and where indexing left off- If your token expires mid-export, the script saves progress and exits gracefully
- Just run again with a fresh Bearer token — already-downloaded conversations are skipped
- The conversation index is also built incrementally, resuming from the last page fetched
--bearer <token> Bearer/access token (or set CHATGPT_BEARER_TOKEN env var; prompted if omitted)
--token <token> Session token (alternative auth, personal accounts only; or set CHATGPT_SESSION_TOKEN)
--account-id <id> ChatGPT Teams account ID (auto-detected from token when possible)
-o, --output <dir> Output directory (default: ./exports)
--format <format> Export format: json | markdown | both (default: both)
--throttle <seconds> Minimum time between API requests in seconds (default: 60)
--update Re-download and overwrite existing conversations
--no-projects Skip project conversations (projects are exported by default)
--projects-only Export only project conversations (skip regular)
--no-files Skip ALL file downloads
--no-images Skip downloading DALL-E images
--no-canvas Skip downloading canvas documents
--no-attachments Skip downloading other file attachments
--no-user-dir Do not nest exports inside a user ID subdirectory
--max <n> Only download the next N conversations this session (also -N, e.g. -7)
--conv <ids> Only download specific conversation ID(s), comma-separated
--proj <ids> Only download specific project ID(s), comma-separated
-n, --non-interactive Run without any interactive prompts (requires --bearer or --token)
--no-summary Suppress the export summary at the end
--no-donate Suppress the donation message/prompt
--verbose Show detailed request/response info
--help Show help message
To avoid having to paste your token each time:
export CHATGPT_BEARER_TOKEN="eyJ..."
npx export-chatgptThe only interactive prompt is the bearer token — if neither --bearer, --token, nor the corresponding environment variables are provided, the script will prompt you to enter a token.
# Export everything (conversations, projects, images, canvas, attachments)
npx export-chatgpt
# Skip project conversations
npx export-chatgpt --no-projects
# Only project conversations, skip file downloads
npx export-chatgpt --projects-only --no-files
# Export only JSON format (default is both json and markdown)
npx export-chatgpt --format json
# Export to custom directory
npx export-chatgpt --output ~/Documents/chatgpt-backup
# Slower requests to avoid rate limiting
npx export-chatgpt --throttle 90
# Re-download all conversations (overwrite existing)
npx export-chatgpt --update
# Skip images but keep canvas and attachments
npx export-chatgpt --no-images
# Resume after token expiry — just run again with a fresh token
npx export-chatgpt
# Limit to 10 conversations this session
npx export-chatgpt --max 10
# Non-interactive mode (for scripts/CI — requires --bearer or ENV variable as below)
CHATGPT_BEARER_TOKEN="eyJ..." npx export-chatgpt --non-interactiveThe Markdown output includes YAML frontmatter and handles multiple content types:
| Content Type | Rendering |
|---|---|
| Text messages | Standard Markdown |
| Code results | Fenced code blocks |
| Images/files |  links or [Image: {id}] |
| Canvas documents |  links |
| Browsing results | Blockquote with "Browsing Result" header |
| Thinking/reasoning (o1/o3) | Collapsible <details> block |
| Reasoning recap | Italic summary |
| Deep research results | "Assistant (Deep Research: title)" header |
| Tool messages | Blockquote with tool name |
Example frontmatter:
---
title: "My conversation title"
id: abc123...
create_time: 2025-01-15T10:30:00.000Z
update_time: 2025-01-15T11:00:00.000Z
model: gpt-4o
project_id: g-abc123...
---- Bearer tokens expire quickly — get a fresh one from DevTools
- Make sure you copied the entire token (starts with
eyJ) - For Teams accounts, make sure to include
--account-id(or let the tool auto-detect it) - Progress is saved automatically, so just re-run with a new token
This likely means one of:
- Teams account without
--account-id: You need to pass your account ID for Teams workspaces - You're logged into a different workspace than expected
- The account genuinely has no conversations
If you see 429 errors, the script will automatically wait and retry. You can also increase the throttle:
npx export-chatgpt --throttle 90- Uses your Bearer token directly for API authentication (or exchanges a session token for one)
- Incrementally fetches the conversation list via
/backend-api/conversations(28 per page), saving progress after each page - Downloads each conversation's full content via
/backend-api/conversation/{id}, tracking completed downloads - Fetches the project list via
/backend-api/gizmos/snorlax/sidebar, then indexes and downloads each project's conversations (use--no-projectsto skip) - Scans conversation data for file references (
image_asset_pointer,canvas_asset_pointer) and downloads via/backend-api/files/download/{id}(use--no-filesto skip) - Saves to JSON and/or Markdown files
- On auth failure, saves all progress and exits — re-running skips already-completed work
MIT