Users treat conversation content as their work product — research notes, code snippets, draft copy, meeting summaries. When the only way to extract that work is to scroll-select-copy message by message, users feel locked in, and locked-in users are hostile users. Export is a trust signal: it tells the customer "your data is yours," which also happens to be a GDPR Article 20 data-portability requirement for EU users and a hard requirement of most enterprise procurement checklists.
Medium because the friction is real but the data is not truly trapped — just painful to extract manually.
Ship a Markdown export first — it's one function and covers 90% of the use cases. Map messages to **Role:** content blocks joined with ---, wrap in a Blob, trigger a download with a[download]. Add JSON export once you have power users asking. Implement in src/components/chat/export-menu.tsx.
const blob = new Blob([markdown], { type: 'text/markdown' })
const a = Object.assign(document.createElement('a'), { href: URL.createObjectURL(blob), download: 'conversation.md' })
a.click()
ID: ai-ux-patterns.feedback-control.export-conversation
Severity: medium
What to look for: Count all export-related actions in conversation management UI: download buttons, export menu items, save-to-file options. For each, enumerate the supported export format (Markdown, plain text, JSON, PDF). Look for download handlers (URL.createObjectURL, Blob creation, a[download] element triggers) or server-side export API routes at app/api/conversations/ paths. At least 1 export format must produce a complete conversation transcript.
Pass criteria: A conversation can be exported to at least 1 portable format (Markdown, text, JSON, PDF) via a download or copy action. Report the count on pass: "X export formats supported."
Fail criteria: No export functionality found. Conversations can only be read within the application.
Skip (N/A) when: Same as regeneration-button.
Detail on fail: "No export, download, or conversation serialization found. Conversation data is accessible only within the application.".
Remediation: Export is a trust feature — users want to know they can take their data with them. A Markdown export is straightforward to implement:
const handleExportMarkdown = () => {
const markdown = messages
.map(m => `**${m.role === 'user' ? 'You' : 'AI'}:** ${m.content}`)
.join('\n\n---\n\n')
const blob = new Blob([markdown], { type: 'text/markdown' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `conversation-${new Date().toISOString().slice(0, 10)}.md`
a.click()
URL.revokeObjectURL(url)
}