Back to Projects

Export MD

A browser extension that saves any Claude, ChatGPT or Gemini conversation as a clean .md file. One button, next to the chat title. Headings, lists, code blocks and tables all survive.

JavaScript plain JS, Manifest V3 — no build step, no bundler, no dependencies
DOM → Markdown a hand-written converter, not a library — headings, lists, tables, code, math
Python generates the icon set with Pillow
Steal the code Install it
claude.ai chatgpt.com gemini.google.com Chrome · Edge · Brave · Arc

A chat you want to keep is usually a chat you want to use again — paste back into another model, drop into notes, hand to someone else. Copy-paste destroys the structure. Screenshots destroy the text. PDF exports bloat it.

Markdown keeps the structure and is the cheapest format in tokens, so it's the clearest thing to paste back into an AI tool. It's also plain text, so it opens anywhere: Notes, Word, Obsidian, Notion, VS Code.

01Rewinds the chat to the very top
02Sweeps down in overlapping steps
03Converts each message to Markdown
04Downloads, named after the chat

The scrolling isn't for show. These sites virtualise the message list — older messages genuinely don't exist in the DOM until you scroll near them. So the extension walks the whole conversation, collecting as it renders, and puts your scroll position back where it found it.

One adapter per site

Claude, ChatGPT and Gemini each get an adapter covering four things: where the button goes, which element actually scrolls, how to find a message, and how to read the chat title. When one of them redesigns — and they do, constantly — the fix is a couple of selectors in one object, not a rewrite.

The button that refuses to fall off

Anchors are ranked best-first, starting from the real chat-title element. If the page mounts a better anchor later — which happens constantly on apps that swap their header after load — the injector upgrades to it. That's what keeps "Export MD" sitting next to the chat name instead of drifting somewhere random.

Deduplication by content hash

Overlapping scroll steps mean the same message gets seen several times. Each one is keyed by author plus a slice of its content, so a long chat exports once — in document order — instead of three times in a shuffled one.

A hand-written DOM → Markdown converter

No Turndown, no dependencies. It walks the node tree itself and handles headings, bold, italics, strikethrough, links, nested lists, blockquotes, tables, images, inline code, fenced code with language detection, and MathML. Buttons, toolbars and screen-reader-only nodes get stripped before conversion, so the file has no UI junk in it.

Nowhere. There's no server and no account. It reads the page you're already looking at and saves a file to your computer. The extension asks for no permissions beyond running on those three sites — check manifest.json; there's no permissions block at all.