- JavaScript 93.3%
- CSS 3.6%
- HTML 3.1%
| icons | ||
| images | ||
| popup | ||
| src | ||
| background.js | ||
| manifest.json | ||
| README.md | ||
| SECURITY.md | ||
Claude Chat Exporter
A Firefox extension that saves Claude web conversations as one self-contained file.
If you are looking for something similar, but for Claude Code, check out this repository by Simon Willison: https://github.com/simonw/claude-code-transcripts.
The default chat sharing provided by Anthropic is insufficient - many parts of the conversation are missing (prompts are collapsed, thinking and tool calls are not visible and so on). This extension uses the cached credentials to make an API request for the conversation in JSON format. The json file contains all information about the conversation (including sensitive metadata); the HTML is reconstructed from this with the option of stripping sensitive metadata.
While some effort has been taken to ensure security, there are no guarantees. This extension has access to the network and sensitive data - use at your own risk!
Disclaimer
This code, in it's entirety, was automatically generated by Anthropic's Claude Opus 5. Only the ability to export the chat was of interest. There are some security concerns, but these were accepted - the extension is only loaded in a sandboxed environment when required.
The transcripts are available at: https://files.krishnaraj.dev/projects/2026-07-27-claude-chat-export-firefox-ext/.
The rest of this README was automatically generated.
Install
Temporary (resets when Firefox closes):
- Go to
about:debugging#/runtime/this-firefox - Load Temporary Add-on…
- Pick
manifest.jsoninside this folder
Permanent: zip the folder's contents (not the folder itself), rename to .xpi, and either
sign it at addons.mozilla.org or install it in
Firefox Developer Edition / Nightly with xpinstall.signatures.required set to false
in about:config.
Use
Open a conversation, click the toolbar button, then Save files. You get two:
claude-<title>-<date>.html and, unless you turn it off, claude-<title>-<date>.json.
Ctrl+Shift+E does the same thing without opening the popup.
Options, remembered between sessions:
| Option | Effect |
|---|---|
| Thinking collapsed | Thinking blocks start closed |
| Your prompts collapsed | Prompts start closed, showing a one-line preview |
| Tool calls expanded | Tool calls and results start open |
| Dark | The saved file opens in its dark theme |
| Tool calls and results | Include them at all |
| Images, embedded in the file | Fetch images and inline them as data URLs |
| Raw JSON next to the HTML | Also write the server's conversation record, verbatim |
| Ask where to save | Show the file picker instead of using the downloads folder |
| Scrub identifying metadata | Drop the metadata block and the source link; write times in UTC |
Why it doesn't snapshot the DOM
SingleFile serialises what's in the page. That doesn't work here: claude.ai virtualises long threads, so turns far from the viewport aren't in the DOM at all, and opening a collapsed block near the top changes the measured row heights, which unmounts rows further down — the behaviour you described where expanding at the top collapses the bottom.
So this reads the conversation record from claude.ai's own endpoint
(/api/organizations/{org}/chat_conversations/{id}) using your existing session, and rebuilds
the page from that. You get every turn, including thinking blocks that were never scrolled into
view. If that request fails, it falls back to reading the page, and the saved file says so in
its header.
Editing a message forks the conversation, so the extractor walks parent → child and keeps the most recent branch at each fork. Any superseded messages are counted in the file's header.
How the saved file looks
It follows claude.ai: ivory ground (#faf9f5), warm dark text (#141413), terracotta accent
(#d97757), your messages in rounded ivory bubbles, Claude's replies as plain serif text with
no container, thought processes as a muted "Thought process" row with a rule down the left, and
dark rounded code blocks with a language bar. Dark mode uses the warm greys rather than black.
Fonts are system stacks — a serif (ui-serif, Georgia, …) for Claude's prose and a sans for
your messages and the chrome — because a file that has to work offline can't fetch webfonts.
So it reads like claude.ai rather than matching it glyph for glyph.
In the saved file
- Expand all / Collapse all, and a Thinking toggle that only affects thought processes
- Find in transcript — filters to matching turns and opens matching blocks
- Theme toggle, remembered per file
- Print — expands everything first, so nothing is lost on paper
- A prompt index down the left on wide screens; every message has an anchor (
#t7) - An expanded prompt keeps a faint chevron in its corner; collapsed, it becomes a single line
- Copy buttons on code blocks
Collapsing uses native <details>, so opening one block can't affect another, and the browser's
own find (Ctrl+F) reaches closed blocks in Firefox.
Layout of the source
manifest.json MV3, Firefox-flavoured
background.js writes the file, handles the keyboard shortcut
popup/ the toolbar panel
src/markdown.js small Markdown renderer (no dependencies — the file must work offline)
src/extract.js reads and normalises the conversation
src/render.js builds the HTML document, including its CSS and script
src/content.js ties the two together in the page
What ends up in each file
The HTML is the readable transcript: the active branch of the conversation, thinking blocks, tool calls, extracted text from files you uploaded, and any images that were embedded. It loads nothing from the network when opened — no fonts, no scripts, no images. The only outbound thing in it is a link back to the conversation, which carries its UUID.
The JSON is the response from claude.ai's endpoint, unmodified and pretty-printed. It is a superset of the HTML and holds things the transcript deliberately leaves out:
- messages from branches you edited away or regenerated past
- message, conversation, and account or organisation identifiers
preview_urlvalues for uploaded files, which can be signed, time-limited links- exact timestamps on every message
- full extracted text of every attachment, and full tool inputs and outputs
If the page fallback was used instead of the endpoint, the JSON is the normalised reading and
says so in a _note field at the top.
Scrubbing
With the toggle on, the HTML loses three things:
- the
cce-metablock, which held the conversation UUID, the source URL, the model, and the ISO timestamps - the link back to the conversation in the header, which was the other place the UUID appeared
- local time. Every timestamp becomes
2026-07-20 09:14 UTC, formatted by hand rather than throughtoLocaleString, since a localised string leaks the reader's locale through the date order even after the zone is fixed.
After scrubbing there is no conversation UUID anywhere in the file and nothing links it to a claude.ai URL.
It does not touch, by design:
- the conversation title, which Claude wrote and which appears in
<title>, the header, and the filename — the filename travels with the file when you send it - the transcript itself, including uploaded filenames and their extracted text
- EXIF in embedded images; the extension copies the bytes claude.ai serves
- the JSON companion, which is still the raw record. A scrubbed HTML sitting next to an unscrubbed JSON is the obvious way to undo the whole exercise.
Sharing
The extension has no hardcoded credentials, no analytics, and no server of its own — see
SECURITY.md for the audit. Sharing the code is fine.
Sharing the output is a judgement call, and the two files are not equally safe:
- Anything you typed into the chat is in both files, including anything you pasted — API keys, tokens, and internal documents included. Nothing redacts that for you.
- The HTML shows one branch. The JSON shows every branch, so a prompt you rewrote because the first version said too much is still in there. This is the most common surprise.
- The JSON's file
preview_urlvalues may be signed links. Treat them as live credentials until they expire. - Reading either file requires no login, so anyone you send it to sees everything in it.
For a transcript you intend to publish, share the HTML and keep the JSON. Skim the JSON before it goes anywhere, or leave the checkbox off.
Limits
- Images larger than 6 MB, or past 20 MB total, are skipped and noted in the popup. Images that cannot be embedded are listed by name rather than linked, so the saved page never calls home.
- Syntax highlighting isn't included; code keeps its language label and monospace treatment.
- LaTeX is left as written rather than typeset.
- The endpoint it reads is claude.ai's internal one, so a redesign could change its shape. The page fallback covers that case, partially.
