Created
April 12, 2026 10:33
-
-
Save bquast/e26812c23bc4829531a465a00e86a160 to your computer and use it in GitHub Desktop.
Export Claude conversation to markdown
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (() => { | |
| const title = document.title.replace(' - Claude', '').trim(); | |
| const lines = [`# ${title}\n`]; | |
| // Grab every turn in the conversation | |
| const turns = document.querySelectorAll('[data-testid="user-message"], .font-claude-response-body, .standard-markdown'); | |
| // Better approach: walk the full message list | |
| // User messages | |
| const userMsgs = [...document.querySelectorAll('[data-testid="user-message"]')]; | |
| // Claude responses — each lives inside a .standard-markdown container | |
| const claudeMsgs = [...document.querySelectorAll('.standard-markdown')]; | |
| // Interleave by DOM order | |
| const all = [ | |
| ...userMsgs.map(el => ({ el, role: 'user' })), | |
| ...claudeMsgs.map(el => ({ el, role: 'claude' })) | |
| ].sort((a, b) => { | |
| const pos = a.el.compareDocumentPosition(b.el); | |
| return pos & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1; | |
| }); | |
| function nodeToMd(node, indent = '') { | |
| if (node.nodeType === Node.TEXT_NODE) return node.textContent; | |
| const tag = node.tagName?.toLowerCase(); | |
| const children = () => [...node.childNodes].map(n => nodeToMd(n, indent)).join(''); | |
| if (!tag) return children(); | |
| switch (tag) { | |
| case 'p': return children() + '\n\n'; | |
| case 'br': return '\n'; | |
| case 'strong': case 'b': return `**${children()}**`; | |
| case 'em': case 'i': return `*${children()}*`; | |
| case 'code': return node.closest('pre') ? children() : `\`${children()}\``; | |
| case 'pre': return '```\n' + node.textContent.trim() + '\n```\n\n'; | |
| case 'h1': return `# ${children()}\n\n`; | |
| case 'h2': return `## ${children()}\n\n`; | |
| case 'h3': return `### ${children()}\n\n`; | |
| case 'h4': return `#### ${children()}\n\n`; | |
| case 'ul': return [...node.children].map(li => `- ${nodeToMd(li, indent + ' ').trim()}`).join('\n') + '\n\n'; | |
| case 'ol': return [...node.children].map((li, i) => `${i+1}. ${nodeToMd(li, indent + ' ').trim()}`).join('\n') + '\n\n'; | |
| case 'li': return children(); | |
| case 'blockquote': return children().split('\n').map(l => `> ${l}`).join('\n') + '\n\n'; | |
| case 'a': return `[${children()}](${node.href})`; | |
| case 'hr': return '---\n\n'; | |
| default: return children(); | |
| } | |
| } | |
| for (const { el, role } of all) { | |
| if (role === 'user') { | |
| const text = el.textContent.trim(); | |
| lines.push(`**You:** ${text}\n`); | |
| } else { | |
| const md = nodeToMd(el).trim(); | |
| lines.push(`**Claude:** ${md}\n`); | |
| } | |
| lines.push('---\n'); | |
| } | |
| const output = lines.join('\n'); | |
| // Download as .md file | |
| const blob = new Blob([output], { type: 'text/markdown' }); | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = `${title.replace(/[^a-z0-9]/gi, '_').toLowerCase()}.md`; | |
| a.click(); | |
| URL.revokeObjectURL(url); | |
| console.log('✅ Exported:', a.download); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment