The share pages are JavaScript-heavy and hard to scrape automatically. Here's the manual approach:
- Open the share URL in Chrome (e.g.,
https://opncd.ai/share/tVj67ILo) - Open DevTools (F12 or Cmd+Option+I)
- Go to Console tab
- Paste this script and press Enter:
// Extract session data from OpenCode share page
(function() {
const messages = [];
const messageEls = document.querySelectorAll('[class*="message"]');
let index = 0;
messageEls.forEach(el => {
const isUser = el.classList.toString().includes('user');
const isAssistant = el.classList.toString().includes('assistant');
if (!isUser && !isAssistant) return;
const content = el.querySelector('[class*="content"], p')?.textContent?.trim() || '';
const thinking = el.querySelector('[class*="thinking"]')?.textContent?.trim();
const toolCalls = [];
el.querySelectorAll('[class*="tool"], button').forEach((tc, i) => {
const name = tc.querySelector('span:first-child')?.textContent?.trim();
if (name && name !== 'Copy') {
toolCalls.push({
id: 'tc-' + index + '-' + i,
name: name,
args: {}
});
}
});
if (content) {
messages.push({
id: 'msg-' + index,
role: isUser ? 'user' : 'assistant',
content: content,
timestamp_ms: index * 5000,
thinking: thinking,
tool_calls: toolCalls.length > 0 ? toolCalls : undefined
});
index++;
}
});
const session = {
id: 'share-' + window.location.pathname.split('/').pop(),
title: document.title || 'Extracted Session',
model: 'unknown',
provider: '',
started_at: new Date().toISOString(),
duration_ms: messages.length * 5000,
task_count: messages.reduce((sum, m) => sum + (m.tool_calls?.length || 0), 0),
messages: messages
};
// Copy to clipboard
copy(session);
console.log('Session data copied to clipboard!');
console.log('Messages: ' + messages.length);
console.log('Tool calls: ' + session.task_count);
console.log('');
console.log('Paste into a .json file and run:');
console.log(' npx ts-node src/index.ts your-file.json output/replay.html');
})();- The JSON will be copied to your clipboard
- Save it to a file (e.g.,
sessions/my-session.json) - Generate the replay:
npx ts-node src/index.ts sessions/my-session.json output/my-session.htmlThe workshop sessions are already extracted:
# Generate replay for session 1
npm run sample
# Generate replay for session 2
npx ts-node src/index.ts sessions/session-1-22-tasks.json output/session-1.html
# Generate with thinking stream
npx ts-node src/index.ts sessions/session-1-22-tasks.json output/session-1-thinking.html --thinking# Extract all three (requires Puppeteer)
npm run extract:all
# Or manually extract each one:
npm run extract https://opncd.ai/share/tVj67ILo
npm run extract https://opncd.ai/share/BDaV3pt1
npm run extract https://opncd.ai/share/bdkwGTDAThe extracted JSON should look like this:
{
"id": "share-tVj67ILo",
"title": "22 tasks in HU",
"model": "mimo-v2.5-free",
"provider": "Build·mimo-v2.5-free",
"started_at": "2026-06-11T13:44:00Z",
"duration_ms": 180000,
"task_count": 8,
"messages": [
{
"id": "msg-0",
"role": "user",
"content": "what 22 tasks are requested in HU?",
"timestamp_ms": 0
},
{
"id": "msg-1",
"role": "assistant",
"content": "The user is asking about...",
"thinking": "Let me search for HU tasks...",
"timestamp_ms": 5000,
"tool_calls": [
{
"id": "tc-1-0",
"name": "search_files",
"args": { "pattern": "*.csv" }
}
]
}
]
}- Thinking streams: Add a
thinkingfield to assistant messages to show the reasoning process - Tool calls: The
namefield should match the tool name (e.g.,search_files,read_file,terminal) - Timestamps: Use milliseconds from session start. The animation will pace based on these.
- Custom CSS: Pass
css_overridesto customize the theme:
renderSession(session, outputPath, {
css_overrides: `
:root {
--bg-primary: #1a1a2e;
--accent-blue: #00d4ff;
}
`
});