ChatGPT to Claude
Migrate all your ChatGPT conversations into Claude with two browser-console scripts — no API keys, no extensions, no external tools.
ChatGPT to Claude
Migrate all your ChatGPT conversations into Claude with two browser-console scripts — no API keys, no extensions, no external tools.
Note: Conversations are exported as a flat zip of
.txtfiles — ChatGPT project/folder structure is not preserved. The importer places every conversation into a single Claude Project of your choosing.
| Step | Script | Where to run | What it does |
|---|---|---|---|
| 1 | ChatGPTConversationExporter.js |
chatgpt.com | Exports every conversation as a .txt inside a .zip. |
| 2 | ClaudeConversationImporter.js |
claude.ai | Reads the .zip, lets you pick a Claude Project, and imports each conversation as a new Claude chat. |
Both scripts work the same way: open F12 → Console, paste the script, hit Enter. They reuse the Authorization token and Cookie the browser already holds for the active session — nothing to configure.
Table of Contents
- Requirements
- Step 1 — Export from ChatGPT
- Step 2 — Import into Claude
- Privacy & Security
- UI Overlays
- Limitations & Known Constraints
- Troubleshooting
- License
Requirements
- A modern browser (Chrome, Edge, Firefox, etc.).
- An active, logged-in session on chatgpt.com (Step 1) and claude.ai (Step 2).
- No extensions, API keys, or external tools required.
Step 1 — Export from ChatGPT
Usage
- Go to chatgpt.com and make sure you are logged in.
- Press F12 (or right-click → Inspect) to open Developer Tools.
- Click the Console tab.
- Copy the entire contents of
ChatGPTConversationExporter.js. - Paste it into the console and press Enter.
- A full-screen progress overlay will appear — keep the tab open until the export finishes.
- When complete, a
chatgpt_export_YYYY-MM-DD.zipfile will download automatically.
How It Works
- URL Check — Verifies the script is running on
chatgpt.com. If the hostname does not match, an alert is shown and the script exits immediately. - Authentication — Retrieves your session access token by calling
/api/auth/session. The token is sent as aBearertoken in theAuthorizationheader for all subsequent requests. - Discovery — Paginates through
/backend-api/conversations(100 conversations per page, ordered byupdated) to build a complete list of every conversation in your account. - Project Scan — Fetches all ChatGPT Projects via
/backend-api/projectsand, for each project, paginates through/backend-api/conversations?project_id={id}. Any conversations not already seen are merged into the main list. This catches conversations hidden behind the sidebar’s “Show more” ellipsis. - Fetch — For each conversation, fetches the full message tree from
/backend-api/conversation/{id}. - Extract — Walks the message tree using a depth-first traversal (iterative stack). Each node’s
message.content.partsarray is joined into plain text. Messages are labelled by role (You,ChatGPT,System,Tool). - Package — Writes each conversation as a
.txtfile inside a zip archive using a built-in pure-JavaScript zip writer (STORE method, no compression). All files are stored flat (no folder nesting). - Download — Generates the zip blob in-browser and triggers an automatic download.
ChatGPT API Endpoints Used
| Endpoint | Method | Purpose |
|---|---|---|
/api/auth/session |
GET | Retrieve the current session access token |
/backend-api/conversations?offset={n}&limit=100&order=updated |
GET | Paginate through the conversation list |
/backend-api/projects?offset={n}&limit=100&order=most_recent |
GET | Discover all ChatGPT Projects |
/backend-api/conversations?project_id={id}&offset={n}&limit=100 |
GET | Paginate conversations inside a specific project |
/backend-api/conversation/{id} |
GET | Fetch the full message tree for a single conversation |
Configuration
| Variable | Default | Description |
|---|---|---|
DELAY_MS |
1200 |
Milliseconds to wait between API calls (rate-limiting / politeness delay). |
BASE |
/backend-api |
Base path for ChatGPT backend API calls. |
Conversation Format
Each .txt file is formatted as:
======================================================================
Conversation Title
======================================================================
Date: 1/15/2025, 3:42:00 PM
--- You ---
User message text
--- ChatGPT ---
Assistant response text
======================================================================
End: Conversation Title
======================================================================
Roles are mapped as follows:
| API role | Display label |
|---|---|
user |
You |
assistant |
ChatGPT |
system |
System |
tool |
Tool |
| anything else | raw role string |
Duplicate Filename Handling
If two conversations have the same title, subsequent files get a numeric suffix:
Some Title.txt
Some Title (1).txt
Some Title (2).txt
Filenames are sanitized: characters < > : " / \ | ? * are replaced with _, leading/trailing dots are stripped, and names are truncated to 100 characters.
Built-in Zip Writer
The exporter includes a minimal, dependency-free zip writer implemented in pure JavaScript. It builds a valid ZIP archive using the STORE method (no compression):
- Encodes file content as UTF-8 and computes a CRC-32 checksum for each entry.
- Writes Local File Headers followed by raw file data.
- Writes a Central Directory with one entry per file.
- Writes an End of Central Directory (EOCD) record.
- Returns the result as a
Blobfor immediate download.
Note: No external libraries are loaded. This avoids Content Security Policy (CSP) issues on chatgpt.com that block third-party CDN scripts.
Step 2 — Import into Claude
Usage
- Go to claude.ai and make sure you are logged in.
- Press F12 (or right-click → Inspect) to open Developer Tools.
- Click the Console tab.
- Copy the entire contents of
ClaudeConversationImporter.js. - Paste it into the console and press Enter.
- An overlay will appear. Click Minimize & Capture, then send any message in Claude's chat. This lets the script capture your session's auth headers.
- The overlay reappears with a file picker — select your
chatgpt_export_YYYY-MM-DD.zipfile. - If you belong to multiple Claude organizations (e.g., Free + Team), a picker appears — choose your org.
- A project picker appears — choose the Claude Project to import into. (Create one in Claude first if you haven't already.)
- The script imports every conversation as a new chat inside the chosen project.
- When finished, a summary screen shows conversations imported and errors. Click Close to dismiss.
How It Works
- URL Check — Verifies the script is running on
claude.ai. If the hostname does not match, an alert is shown and the script exits immediately. - Auth Capture — The overlay minimizes and the script intercepts
window.fetchto capture auth headers and the active model name from the next Claude API call the user triggers (e.g., sending a message). These headers are replayed via un-patched nativefetch(obtained from a hidden iframe) for all subsequent API calls. - File Selection — Presents a styled file picker (
<input type="file" accept=".zip">). - Parse — Reads the zip entirely in-browser using a built-in pure-JavaScript zip reader (no external libraries). All
.txtfiles are extracted into a flat list regardless of any folder structure in the zip. See Built-in Zip Reader. - Organization Picker — Fetches all Claude organizations from
/api/organizations. If you belong to multiple orgs (e.g., personal Free plan + a Team workspace), a picker lets you choose which one. Single-org accounts skip this step. - Project Picker — Lists your existing Claude Projects and presents a picker. All conversations will be imported into the chosen project.
- Create Conversations — For each
.txtfile, a new chat conversation is created viaPOST /api/organizations/{orgId}/chat_conversationswith the conversation title andproject_uuid. The conversation content is then sent as the first message via the streaming completion endpoint, and the response is drained so the server commits the conversation. - Summary — Displays a completion screen with conversations imported and errors.
Why does this work? Claude's frontend wraps
window.fetchand adds auth headers (session tokens, client identifiers) internally. Our script captures those headers by intercepting a real API call, then uses un-patched nativefetch(from a hidden iframe) to make its own requests with the same credentials. This bypasses the wrapper entirely while preserving full authentication.
Claude API Endpoints Used
| Endpoint | Method | Purpose |
|---|---|---|
/api/organizations |
GET | Retrieve the current user's organization UUID |
/api/organizations/{orgId}/projects |
GET | List existing projects (for project picker) |
/api/organizations/{orgId}/chat_conversations |
POST | Create a new chat conversation (uuid, name, project_uuid) |
/api/organizations/{orgId}/chat_conversations/{convId}/completion |
POST | Send a message to a conversation (streaming response) |
Configuration
| Variable | Default | Description |
|---|---|---|
DELAY_MS |
800 |
Milliseconds to wait between API calls (rate-limiting / politeness delay). |
Built-in Zip Reader
The importer includes a minimal, dependency-free zip reader implemented in pure JavaScript. It works by:
- Scanning backwards from the end of the
ArrayBufferto locate the End of Central Directory (EOCD) signature (0x06054b50). - Reading the Central Directory entries to discover each file's name, compression method, compressed size, and local header offset.
- Parsing each Local File Header to calculate the exact data start position.
- Decompressing each entry: STORE (method 0) entries are used as-is; DEFLATE (method 8) entries are decompressed using the browser's built-in
DecompressionStreamAPI. - Decoding the resulting bytes as UTF-8 text.
Note: The exporter generates STORE-method (uncompressed) zips for maximum compatibility. The importer also handles DEFLATE-compressed zips produced by other tools. Directories and zero-length entries are skipped.
Privacy & Security
- No data leaves your browser — both scripts run entirely within your active browser session. Conversations are read from one service and written to another using the same browser that already has access.
- No third-party servers — neither script loads external resources. Both operate entirely using built-in browser APIs.
- No API keys — both scripts piggyback on the authentication tokens/cookies your browser already holds for chatgpt.com and claude.ai.
- Credentials are never stored — access tokens are used in-memory for the duration of the script and discarded when the page is closed.
UI Overlays
Both scripts render a full-screen overlay with a dark theme (rgba(0,0,0,0.85) backdrop) to show real-time progress:
Exporter Overlay (ChatGPTConversationExporter.js)
- Header — "ChatGPT Conversation Exporter" with a purple-to-green gradient.
- Progress bar — Animated fill from 0% to 100% as conversations are processed.
- Counter —
{current} / {total} conversations. - Status line — Current operation description.
- Current item — Monospace display of the conversation title being exported.
- Log panel — Scrollable panel showing warnings (yellow) and errors (red).
- Close button — Appears after export completes.
Importer Overlay (ClaudeConversationImporter.js)
- Header — "Claude Conversation Importer" with a warm brown/copper gradient.
- File selection view — A styled button to trigger the file picker.
- Organization picker — Buttons for each Claude org (shown only for multi-org accounts).
- Project picker — Buttons for each existing Claude Project.
- Progress view — Same layout as the exporter (counter, progress bar, status, log).
- Completion view — Checkmark icon, summary statistics, and a Close button.
Limitations & Known Constraints
| Area | Detail |
|---|---|
| Rate limiting | Both scripts use a fixed delay between API calls (DELAY_MS). If you hit rate limits, increase the value. |
| Project structure | ChatGPT project/folder organization is not preserved. All conversations are exported as flat .txt files and imported into a single Claude Project. |
| Conversation size | Very large conversations may approach Claude's knowledge document size limits. |
| Zip compression | The exporter generates STORE (uncompressed) zips. The importer supports both STORE and DEFLATE. Other compression methods are not supported. |
| Browser tab | The export/import tab must remain open and in the foreground for the full duration of the operation. |
| Session expiry | Long-running exports (thousands of conversations) may encounter session token expiration. Re-run the script if this happens. |
| Message types | Only text content is extracted. Images, file attachments, and DALL-E generations are not included. |
Troubleshooting
| Problem | Solution |
|---|---|
| "…must be run on chatgpt.com / claude.ai" | You pasted the script on the wrong website. Navigate to the correct domain first. The exporter only runs on chatgpt.com; the importer only runs on claude.ai. |
| "No accessToken in session response" | Your ChatGPT session may have expired. Refresh the page, ensure you are logged in, and try again. |
| "Not a valid zip file (no EOCD found)" | The selected file is not a valid zip archive. Make sure you are selecting the .zip output from Step 1. |
| "Failed to fetch orgs" | Your Claude session may have expired. Refresh claude.ai, log in, and re-run the importer. |
| HTTP 429 errors | You are being rate-limited. Increase DELAY_MS (e.g., to 2000 or higher) and try again. |
| Script does nothing | Check the browser console for errors. Some browsers require you to type allow pasting first before pasting scripts into the console. |
| Missing conversations | The exporter skips conversations with zero extractable text messages. Check the log panel for "No messages" warnings. |
License
This project is provided as-is for personal use. Use at your own risk.