Export X (Twitter) Bookmarks to CSV – Simple Script with Metrics
Easily export your X (Twitter) bookmarks to CSV with this simple Tampermonkey script. Extract tweets, usernames, likes, views, and more for analysis, automation, or research.
🚀 Export Your X (Twitter) Bookmarks to CSV in Seconds
If you’ve ever saved hundreds of bookmarks on X (formerly Twitter) and later thought “how do I actually use this data?” — you’re not alone.
Bookmarks pile up fast. But exporting them? Not so simple… until now.
This lightweight Tampermonkey script gives you a one-click way to extract all your bookmarks into a clean CSV file — complete with metrics like likes, reposts, and views.
💡 What This Script Does
Instead of manually opening every bookmarked post, this script:
- Scrolls through your bookmarks automatically
- Extracts tweet content, author name, and handle
- Captures engagement data (likes, reposts, replies, views)
- Generates a ready-to-use CSV file
No API. No login hacks. Just clean scraping directly from your browser.
⚙️ How It Works
Once installed, a button appears on your bookmarks page.
Click it → and the script will:
- Start scrolling your bookmarks
- Collect data from each visible tweet
- Avoid duplicates automatically
- Export everything into a CSV file
You’ll even see a live counter updating while it works — so you know it’s doing its job.
📊 What You Get in the CSV
Your exported file includes:
- Name
- Username (handle)
- Tweet content
- Direct tweet URL
- Replies
- Reposts
- Likes
- Views
Perfect for:
- Content research
- Lead generation
- Trend analysis
- Building datasets for automation
🔥 Why This Is Useful
If you're working with automation, scraping, or content systems, this becomes powerful fast.
You can:
- Feed the data into your Python scripts
- Build datasets for AI models
- Track viral content patterns
- Extract leads or niche insights
It turns your bookmarks into structured data — not just saved posts.
🛠️ Setup (Quick)
- Install Tampermonkey
- Add the script
- Open your bookmarks page on X (formerly Twitter)
- Click “Export to CSV”
Done.
⚠️ Small Notes
- Works best when you let it scroll fully
- Large bookmark collections may take a minute
- Data depends on what’s visible in the UI
🎯 Final Thought
Most people save content and forget it.
This flips the game — now your bookmarks become data you can actually use.
// ==UserScript==
// @name X Bookmark Exporter (Pro CSV)
// @namespace http://tampermonkey.net/
// @version 1.5
// @description Export X bookmarks with Metrics, URLs, and dynamic button feedback
// @author Gemini
// @match https://x.com/i/bookmarks
// @match https://twitter.com/i/bookmarks
// @grant none
// ==/UserScript==
(function() {
'use strict';
let extractedData = new Map();
let isScraping = false;
const createBtn = () => {
const btn = document.createElement('button');
btn.id = "gemini-export-btn";
btn.innerText = "Export to CSV";
Object.assign(btn.style, {
position: 'fixed',
top: '12px',
right: '80px',
backgroundColor: '#eff3f4',
color: '#0f1419',
padding: '0 20px',
height: '36px',
borderRadius: '9999px',
fontWeight: '700',
fontSize: '14px',
cursor: 'pointer',
zIndex: '9999',
border: '1px solid rgba(0,0,0,0)',
boxShadow: '0 0 10px rgba(0,0,0,0.3)',
transition: 'all 0.3s ease'
});
btn.onclick = toggleScrape;
document.body.appendChild(btn);
};
const parseMetric = (el, testId) => {
let target = (testId === "views")
? el.querySelector(`a[href$="/analytics"]`)
: el.querySelector(`button[data-testid="${testId}"]`);
if (!target) return "0";
const label = target.getAttribute('aria-label') || "";
// Extract only the numbers and shorthand (K, M) from the label
return label.replace(/[^0-9.KMB]/g, '').trim() || "0";
};
const formatCSVCell = (text) => {
if (!text) return '""';
return `"${text.replace(/"/g, '""').replace(/\n/g, ' ')}"`;
};
const scrapeVisibleTweets = () => {
const tweets = document.querySelectorAll('div[data-testid="cellInnerDiv"]');
tweets.forEach(tweet => {
const tweetText = tweet.querySelector('div[data-testid="tweetText"]')?.innerText || "";
const userContent = tweet.querySelector('div[data-testid="User-Name"]')?.innerText || "";
const timeLink = tweet.querySelector('time')?.parentElement;
const tweetURL = timeLink ? `https://x.com${timeLink.getAttribute('href')}` : "";
// Keying by URL to avoid duplicates precisely
const uniqueKey = tweetURL || (userContent + tweetText);
if (tweetText && !extractedData.has(uniqueKey)) {
const parts = userContent.split('\n');
extractedData.set(uniqueKey, {
name: parts[0] || "Unknown",
handle: parts[1] || "",
content: tweetText,
url: tweetURL,
replies: parseMetric(tweet, "reply"),
reposts: parseMetric(tweet, "retweet"),
likes: parseMetric(tweet, "like"),
views: parseMetric(tweet, "views")
});
}
});
};
const toggleScrape = async () => {
if (isScraping) return;
isScraping = true;
const btn = document.getElementById('gemini-export-btn');
btn.style.backgroundColor = "#1d9bf0"; // Change to X Blue during extraction
btn.style.color = "#ffffff";
let lastHeight = 0;
let noChangeCount = 0;
while (noChangeCount < 3) {
scrapeVisibleTweets();
btn.innerText = `Extracting: ${extractedData.size}...`;
window.scrollBy(0, window.innerHeight);
await new Promise(r => setTimeout(r, 2000));
let newHeight = document.documentElement.scrollHeight;
if (newHeight === lastHeight) {
noChangeCount++;
} else {
noChangeCount = 0;
}
lastHeight = newHeight;
}
downloadCSV();
// Success State
btn.innerText = "Done ✓";
btn.style.backgroundColor = "#00ba7c"; // Success Green
setTimeout(() => {
btn.innerText = "Export to CSV";
btn.style.backgroundColor = "#eff3f4";
btn.style.color = "#0f1419";
isScraping = false;
}, 5000); // 5 second reset as requested
};
const downloadCSV = () => {
const header = "Name,Handle,Tweet Content,Tweet URL,Replies,Reposts,Likes,Views\n";
let rows = "";
extractedData.forEach(item => {
rows += `${formatCSVCell(item.name)},` +
`${formatCSVCell(item.handle)},` +
`${formatCSVCell(item.content)},` +
`${formatCSVCell(item.url)},` +
`${formatCSVCell(item.replies)},` +
`${formatCSVCell(item.reposts)},` +
`${formatCSVCell(item.likes)},` +
`${formatCSVCell(item.views)}\n`;
});
const blob = new Blob(["\uFEFF" + header + rows], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `x-bookmarks-${new Date().toISOString().split('T')[0]}.csv`;
a.click();
};
window.addEventListener('load', () => setTimeout(createBtn, 2000));
})();