SaveAsMD bookmarklet v1.0.1
Saves the open claude.ai conversation as a Markdown file. Turns are headed ## Operator and ## Claude. The file name is the conversation title plus a date-time stamp, so a re-save never overwrites an earlier one.
Change from v1.0.0: the script no longer contains any backslash characters, so nothing can be damaged if a copy/paste step strips them (v1.0.0 failed with an invalid regular expression for that reason).
Install (Chrome, Opera, Edge, Firefox)
- Show the bookmarks bar (Chrome/Edge: Ctrl+Shift+B; Opera: Settings > Browser > User interface > Show bookmarks bar).
- Edit your existing
Save as MD bookmark (or add a new one) and replace its URL box with the single line below, the whole line, starting with javascript:. - Open any conversation and click the bookmark. A
.md file downloads.
If the browser strips the javascript: prefix when pasting into the box, type javascript: by hand first, then paste the rest.
Script (one line)
javascript:(function(){ var V='1.0.1'; console.log('SaveAsMD v'+V); var B=String.fromCharCode(96),F=B+B+B,H=String.fromCharCode(35),N=String.fromCharCode(10),T=String.fromCharCode(9),BS=String.fromCharCode(92); var WS=new RegExp('[ '+N+T+String.fromCharCode(13)+']+','g'); var TRAIL=new RegExp('[ '+T+']+'+N,'g'); var MANY=new RegExp(N+'{3,}','g'); var sel='[data-testid="user-message"],.font-claude-response,.font-claude-message'; var all=[].slice.call(document.querySelectorAll(sel)); var nodes=all.filter(function(n){return !all.some(function(o){return o!==n&&o.contains(n);});}); if(!nodes.length){alert('SaveAsMD v'+V+': no turns found - the page selectors need updating');return;} function md(n){ if(n.nodeType===3){return n.textContent.replace(WS,' ');} if(n.nodeType!==1){return '';} var t=n.tagName.toLowerCase(); var k=function(){return [].map.call(n.childNodes,md).join('');}; switch(t){ case 'script':case 'style':case 'button':case 'svg':return ''; case 'pre': var c=n.querySelector('code'); var m=c&&(c.className||'').match(/language-([A-Za-z0-9+-]+)/); var s=(c||n).textContent; if(s.charAt(s.length-1)===N){s=s.slice(0,-1);} return N+N+F+(m?m[1]:'')+N+s+N+F+N+N; case 'code':return B+n.textContent+B; case 'p':return N+N+k().trim()+N+N; case 'br':return ' '+N; case 'hr':return N+N+'---'+N+N; case 'h1':case 'h2':case 'h3':case 'h4':case 'h5':case 'h6': return N+N+new Array(+t.charAt(1)+1).join(H)+' '+k().trim()+N+N; case 'strong':case 'b':return '**'+k()+'**'; case 'em':case 'i':return '*'+k()+'*'; case 'a':return '['+k()+']('+n.href+')'; case 'ul':case 'ol': var i=0,g=n.parentNode&&n.parentNode.tagName==='LI'?N:N+N; return g+[].map.call(n.children,function(li){i++;return (t==='ol'?i+'. ':'- ')+md(li).trim().split(N).join(N+' ');}).join(N)+g; case 'blockquote': return N+N+k().trim().split(N).map(function(l){return '> '+l;}).join(N)+N+N; case 'table': var rows=[].map.call(n.querySelectorAll('tr'),function(r){return '| '+[].map.call(r.children,function(d){return d.textContent.trim().split('|').join(BS+'|');}).join(' | ')+' |';}); if(rows.length>1){rows.splice(1,0,'|'+new Array(rows[0].split(' | ').length+1).join(' --- |'));} return N+N+rows.join(N)+N+N; default:return k(); } } var title=(document.title||'conversation').replace(/ *[-|] *Claude *$/,'').trim()||'conversation'; var d=new Date(),p=function(x){return (x<10?'0':'')+x;}; var stamp=d.getFullYear()+p(d.getMonth()+1)+p(d.getDate())+'-'+p(d.getHours())+p(d.getMinutes())+p(d.getSeconds()); var out=H+' '+title+N+N+'*Exported '+d.toLocaleString()+'*'+N+N; nodes.forEach(function(n){ var who=n.matches('[data-testid="user-message"]')?'Operator':'Claude'; var body=md(n).replace(TRAIL,N).replace(MANY,N+N).trim(); out+=H+H+' '+who+N+N+body+N+N; }); var fn=title.replace(/[^A-Za-z0-9 _-]+/g,'').trim().replace(/ +/g,'_')+'_'+stamp+'.md'; var a=document.createElement('a'); a.href=URL.createObjectURL(new Blob([out],{type:'text/markdown'})); a.download=fn; document.body.appendChild(a); a.click(); setTimeout(function(){URL.revokeObjectURL(a.href);a.remove();},1000); })();