🏠 Home 

Claude.ai Chat Exporter (Updated)

Adds "Export Chat" button to Claude.ai (current as of Sonnet 3.7)


Install this script?
// ==UserScript==
// @name         Claude.ai Chat Exporter (Updated)
// @description  Adds "Export Chat" button to Claude.ai (current as of Sonnet 3.7)
// @version      1.1
// @author       Merlin McKean
// @namespace
// @match        https://claude.ai/*
// @grant        GM_xmlhttpRequest
// @grant        GM_download
// @license      MIT
// ==/UserScript==
(function () {
'use strict';
const API_BASE_URL = 'https://claude.ai/api';
// Updated function to make API requests with new headers
function apiRequest(method, endpoint, data = null) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: method,
url: `${API_BASE_URL}${endpoint}`,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
// Add any required authentication headers here
},
data: data ? JSON.stringify(data) : null,
onload: (response) => {
if (response.status >= 200 && response.status < 300) {
resolve(JSON.parse(response.responseText));
} else {
reject(new Error(`API request failed with status ${response.status}`));
}
},
onerror: (error) => {
reject(error);
},
});
});
}
// Function to get the organization ID - updated for new API
async function getOrganizationId() {
try {
const organizations = await apiRequest('GET', '/organizations');
return organizations[0]?.uuid;
} catch (error) {
console.error('Error getting organization ID:', error);
throw error;
}
}
// Updated function to get conversation history
async function getConversationHistory(orgId, chatId) {
return await apiRequest('GET', `/organizations/${orgId}/chat_conversations/${chatId}`);
}
// Function to download data as a file
function downloadData(data, filename, format) {
let content = '';
if (format === 'json') {
content = JSON.stringify(data, null, 2);
} else if (format === 'txt') {
content = convertToTxtFormat(data);
}
const blob = new Blob([content], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.style.display = 'none';
document.body.appendChild(a);
a.click();
setTimeout(() => {
document.body.removeChild(a);
URL.revokeObjectURL(url);
}, 100);
}
// Updated function to convert conversation data to TXT format
function convertToTxtFormat(data) {
let txtContent = `Chat Title: ${data.name}\nDate: ${new Date().toISOString()}\n\n`;
data.chat_messages.forEach((message) => {
const sender = message.sender === 'human' ? 'User' : 'Claude';
txtContent += `${sender}:\n${message.text}\n\n`;
});
return txtContent.trim();
}
// Updated function to create a modern-styled button
function createButton(text, onClick) {
const button = document.createElement('button');
button.textContent = text;
button.style.cssText = `
position: fixed;
bottom: 80px;
right: 20px;
padding: 10px 20px;
background-color: #4a5568;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
z-index: 9999;
font-family: system-ui, -apple-system, sans-serif;
transition: all 0.2s;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
`;
button.addEventListener('mouseover', () => {
button.style.backgroundColor = '#2d3748';
});
button.addEventListener('mouseout', () => {
button.style.backgroundColor = '#4a5568';
});
button.addEventListener('click', onClick);
document.body.appendChild(button);
return button;
}
// Updated function to initialize the export functionality
async function initExportFunctionality() {
const currentUrl = window.location.href;
const chatIdMatch = currentUrl.match(/\/chat\/([a-f0-9-]+)/);
if (chatIdMatch) {
const chatId = chatIdMatch[1];
try {
const orgId = await getOrganizationId();
const button = createButton('Export Chat', async () => {
const format = prompt('Enter export format (json or txt):', 'json');
if (format === 'json' || format === 'txt') {
try {
const chatData = await getConversationHistory(orgId, chatId);
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const filename = `claude-chat_${timestamp}.${format}`;
downloadData(chatData, filename, format);
alert(`Chat exported successfully in ${format.toUpperCase()} format!`);
} catch (error) {
alert('Error exporting chat. Please try again.');
console.error('Export error:', error);
}
} else {
alert('Invalid format. Please enter either "json" or "txt".');
}
});
} catch (error) {
console.error('Error initializing export functionality:', error);
}
}
}
// Function to observe URL changes
function observeUrlChanges() {
let lastUrl = location.href;
new MutationObserver(() => {
const url = location.href;
if (url !== lastUrl) {
lastUrl = url;
initExportFunctionality();
}
}).observe(document, { subtree: true, childList: true });
}
// Initialize the script when the page is ready
function init() {
initExportFunctionality();
observeUrlChanges();
}
// Start the script when the DOM is fully loaded
if (document.readyState === 'complete') {
init();
} else {
window.addEventListener('load', init);
}
})();