Skip to content

Latest commit

 

History

7 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Export MD: save any Claude, ChatGPT or Gemini chat as clean Markdown

Install · How to use · Why Markdown? · Help


Export MD is a free browser extension that saves your AI chats as a PDF, a Markdown file, or JSON.

Open a conversation in Claude, ChatGPT or Gemini, click Export, pick a format, and the whole chat is saved with its headings, lists, code and tables intact. Everything happens in your browser. Nothing is uploaded, and there is no account to make.

Format Good for
PDF Reading, printing, sharing, keeping a record
Markdown Pasting back into an AI tool, notes apps
JSON Scripts and other software

The PDF is laid out as a clean printed document: a title block with the date and message count, numbered turns, your questions in tinted blocks, code blocks labelled with their language, and proper tables. Images come with it, whether you uploaded them or the AI generated them, along with charts and diagrams. It is always light, so it prints and reads well on paper.

Why Markdown?

Markdown keeps the structure of your chat and uses the fewest tokens of any format, so it is the cheapest and clearest thing to paste back into an AI tool. It is also plain text, so it opens anywhere: Notes, Word, Obsidian, Notion, VS Code.

Install it

No coding needed. You do this once. Works in Chrome, Edge, Brave and Arc.

1. Download it. Click the green Code button above, choose Download ZIP, then double-click the ZIP to unzip it. You now have a folder called ExportMD-main. Keep it somewhere safe, because the extension runs from it.

2. Open your extensions page. Paste one of these into your address bar and press Enter:

Browser Paste this
Chrome chrome://extensions
Edge edge://extensions
Brave brave://extensions
Arc arc://extensions

3. Turn on Developer mode. It is a toggle on that page. This just tells your browser you are installing from a folder instead of the store. It is safe.

4. Click Load unpacked and select your ExportMD-main folder.

Done. Pin it from the puzzle-piece icon in your toolbar if you want it handy.

How to use it

  1. Open a chat on Claude, ChatGPT or Gemini.
  2. Click Export next to the chat's name at the top.
  3. Pick PDF, Markdown or JSON.
  4. The page scrolls itself while it collects every message. Let it finish.
  5. Markdown and JSON download straight away. For PDF your browser's print window opens, where you choose Save as PDF as the destination.

Older messages you would have to scroll up to see are included.

Problems

No Export button. Refresh the page and wait a second. These sites change their layouts often, so if it is still missing please open an issue saying which site.

Messages missing. Leave the tab alone until the "Exported" message appears. Long chats take longer.

The PDF opens a print window instead of downloading. That is how it works. Set the destination to Save as PDF and click Save. Going through the print window keeps the text selectable and searchable instead of producing a flat image.

The PDF lost its shading. Tick Background graphics in the print window, under More settings. Most browsers keep it without that, but a few strip backgrounds by default.

A chat with lots of images takes a while. Every image is downloaded and embedded into the file so the PDF works offline and never shows a broken box. Give it a moment; the toast tells you how many it is fetching.

Is my chat sent anywhere? No. It reads the page you are already looking at and saves a file to your computer. No server, no tracking.

For developers

Plain JavaScript, Manifest V3, no build step or dependencies.

Each site has an adapter in content.js covering four things: where the button goes, which element scrolls, how to find messages, and how to read the title. Button anchors are ranked best-first from the real chat-title element, found by matching the page title text rather than by class or test id, and the injector upgrades if a better anchor mounts later. Extraction rewinds the scroll container, sweeps down in overlapping steps so virtualised messages render, and hashes each message to avoid duplicates.

Each message is captured twice: as Markdown, and as HTML with the host page's classes and inline styles stripped. The PDF uses the HTML so tables and nested lists survive, and is rendered by writing a standalone styled document into a hidden same-origin iframe and calling print() on it. A canvas rasteriser would be blocked by these sites' content security policies, and a popup opened after an await has lost its user gesture.

Nothing in the print stylesheet may set page-break-inside: avoid on a message. A message taller than the space left on the page would then move to the next page whole, leaving the previous one half empty. Only table rows avoid breaking; headings and speaker labels use break-after: avoid so they stay with what they introduce. print-color-adjust: exact stops the browser dropping the tints.

Media is captured from the live node before anything is removed, while the clone still lines up index for index: <img> takes currentSrc (what the browser actually chose out of srcset, already absolute), <canvas> is flattened with toDataURL because a clone copies no pixels, and <svg> is kept when it is bigger than 40px and dropped when it is not, which separates diagrams from toolbar icons. SVG subtrees are exempt from attribute stripping, since viewBox and d are the drawing.

Images are then refetched and rewritten as data URIs, so the document carries its own pixels. If a fetch fails on CORS the original URL stays and the same-origin print frame loads it with the page's own cookies. Either way print() waits for every image to settle first: it fires synchronously, so anything still downloading prints as a blank box. The frame is given real dimensions for the same reason, because a zero-sized frame lays out at zero width.

The sanitiser keeps the attributes that carry meaning and drops the rest, so an <ol start="4"> still starts at four and table colspan survives. Code block languages are read off the class names before they are stripped and re-emitted as data-lang, which the stylesheet renders as a chip. Task list checkboxes become glyphs, since the inputs themselves are removed.

When a site redesigns, update that adapter's anchors or messageSelector. Icons are drawn by generate_icons.py (needs Pillow). Pull requests welcome.

License

MIT. See LICENSE.

About

Free browser extension that saves Claude, ChatGPT and Gemini conversations as clean Markdown(most cost effective/easiest way for an llm to understand), in one click.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages