DatafetchPro
    Apr 17, 20265 min read16 views

    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:

    1. Start scrolling your bookmarks
    2. Collect data from each visible tweet
    3. Avoid duplicates automatically
    4. 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)

    1. Install Tampermonkey
    2. Add the script
    3. Open your bookmarks page on X (formerly Twitter)
    4. 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));
    })();
    0