⚡ Community Notes

Other Tools src
v1.0.0 Updated: 2026-03-30 393 lines by @nichxbt

View and contribute to Community Notes on posts,

⚠️ Contributing to Community Notes requires enrollment at

How to Use

  1. Go to: https://x.com/home or a specific tweet
  2. Open DevTools Console (F12)
  3. Edit CONFIG below
  4. Paste and run

Configuration Options

OptionDefaultDescription
tweetUrl''URL of tweet to add a note to
noteText''The note content to write
noteClassification'misleading''misleading', 'not_misleading', or 'might_be_misleading'
rateAsHelpfultruetrue = helpful, false = not helpful
maxTweets30Max tweets to scan for notes

Default Configuration

const CONFIG = {
    // ── Action ───────────────────────────────────────────────
    action: 'view',
    //   'view'     — view Community Notes on visible tweets
    //   'write'    — write a note on the current tweet (requires tweetUrl)
    //   'rate'     — rate existing notes as helpful/not helpful
    //   'browse'   — browse tweets with Community Notes on your timeline

    // ── Write Note Parameters ────────────────────────────────
    tweetUrl: '',                    // URL of tweet to add a note to
    noteText: '',                    // The note content to write
    noteClassification: 'misleading', // 'misleading', 'not_misleading', or 'might_be_misleading'

    // ── Rate Parameters ──────────────────────────────────────
    rateAsHelpful: true,             // true = helpful, false = not helpful

    // ── Browse Settings ──────────────────────────────────────
    maxTweets: 30,                   // Max tweets to scan for notes
    maxScrollAttempts: 20,

    // ── Timing ───────────────────────────────────────────────
    scrollDelay: 2000,
    actionDelay: 2000,
    navigationDelay: 3000,
    typeCharDelay: 30,

    // ── Safety ───────────────────────────────────────────────
    dryRun: true,
  };

Full Script

Copy and paste this entire script into your browser DevTools console on x.com.

/**
 * ============================================================
 * 📝 Community Notes — Production Grade
 * ============================================================
 *
 * @name        communityNotes.js
 * @description View and contribute to Community Notes on posts,
 *              rate existing notes, and browse noted tweets.
 * @author      nichxbt (https://x.com/nichxbt)
 * @version     1.0.0
 * @date        2026-03-30
 * @repository  https://github.com/nirholas/XActions
 *
 * ============================================================
 * 📋 USAGE:
 *
 * 1. Go to: https://x.com/home or a specific tweet
 * 2. Open DevTools Console (F12)
 * 3. Edit CONFIG below
 * 4. Paste and run
 *
 * ⚠️ Contributing to Community Notes requires enrollment at
 *    https://x.com/i/communitynotes
 * ============================================================
 */
// by nichxbt
(() => {
  'use strict';

  const CONFIG = {
    // ── Action ───────────────────────────────────────────────
    action: 'view',
    //   'view'     — view Community Notes on visible tweets
    //   'write'    — write a note on the current tweet (requires tweetUrl)
    //   'rate'     — rate existing notes as helpful/not helpful
    //   'browse'   — browse tweets with Community Notes on your timeline

    // ── Write Note Parameters ────────────────────────────────
    tweetUrl: '',                    // URL of tweet to add a note to
    noteText: '',                    // The note content to write
    noteClassification: 'misleading', // 'misleading', 'not_misleading', or 'might_be_misleading'

    // ── Rate Parameters ──────────────────────────────────────
    rateAsHelpful: true,             // true = helpful, false = not helpful

    // ── Browse Settings ──────────────────────────────────────
    maxTweets: 30,                   // Max tweets to scan for notes
    maxScrollAttempts: 20,

    // ── Timing ───────────────────────────────────────────────
    scrollDelay: 2000,
    actionDelay: 2000,
    navigationDelay: 3000,
    typeCharDelay: 30,

    // ── Safety ───────────────────────────────────────────────
    dryRun: true,
  };

  const SEL = {
    communityNote:  '[data-testid="communityNote"]',
    rateNote:       '[data-testid="rateNote"]',
    writeNote:      '[data-testid="writeNote"]',
    tweet:          'article[data-testid="tweet"]',
    tweetText:      '[data-testid="tweetText"]',
    userName:       '[data-testid="User-Name"]',
    caret:          '[data-testid="caret"]',
  };

  const sleep = (ms) => new Promise(r => setTimeout(r, ms));
  const $ = (s) => document.querySelector(s);
  const $$ = (s) => [...document.querySelectorAll(s)];
  let aborted = false;

  const waitForSelector = async (selector, timeout = 10000) => {
    const start = Date.now();
    while (Date.now() - start < timeout) {
      const el = $(selector);
      if (el) return el;
      await sleep(200);
    }
    return null;
  };

  const typeText = async (element, text) => {
    element.focus();
    for (const char of text) {
      document.execCommand('insertText', false, char);
      element.dispatchEvent(new InputEvent('input', { bubbles: true, data: char, inputType: 'insertText' }));
      await sleep(CONFIG.typeCharDelay);
    }
  };

  const stats = {
    action: CONFIG.action,
    notesFound: 0,
    notesViewed: [],
    noteWritten: false,
    notesRated: 0,
    tweetsScanned: 0,
    startTime: Date.now(),
  };

  window.XActions = {
    abort()  { aborted = true; console.log('🛑 Aborting...'); },
    status() {
      const el = ((Date.now() - stats.startTime) / 1000).toFixed(0);
      console.log(`📊 Notes: ${stats.notesFound} | Rated: ${stats.notesRated} | Tweets: ${stats.tweetsScanned} | ${el}s`);
    },
  };

  const extractTweetInfo = (tweetEl) => {
    const text = tweetEl.querySelector(SEL.tweetText)?.textContent || '';
    const author = tweetEl.querySelector(SEL.userName + ' a')?.textContent || '';
    const link = tweetEl.querySelector('a[href*="/status/"]')?.href || '';
    const time = tweetEl.querySelector('time')?.getAttribute('datetime') || '';
    return { text: text.slice(0, 200), author, link, time };
  };

  const viewNotes = async () => {
    console.log('👁️ Scanning visible tweets for Community Notes...');

    const processedTweets = new Set();
    let scrollAttempts = 0;

    while (scrollAttempts < CONFIG.maxScrollAttempts && !aborted) {
      const tweets = $$(SEL.tweet);

      for (const tweet of tweets) {
        const info = extractTweetInfo(tweet);
        if (!info.link || processedTweets.has(info.link)) continue;
        processedTweets.add(info.link);
        stats.tweetsScanned++;

        // Check for Community Note on this tweet
        const note = tweet.querySelector(SEL.communityNote);
        if (note) {
          const noteText = note.textContent?.trim() || '';
          stats.notesFound++;
          stats.notesViewed.push({
            tweet: info,
            note: noteText.slice(0, 300),
          });

          console.log(`📝 Note found on tweet by ${info.author}:`);
          console.log(`   Tweet: "${info.text.slice(0, 80)}..."`);
          console.log(`   Note: "${noteText.slice(0, 150)}..."`);
          console.log(`   Link: ${info.link}`);
          console.log('');
        }
      }

      window.scrollBy(0, 600);
      await sleep(CONFIG.scrollDelay);
      scrollAttempts++;
    }

    console.log(`✅ Scanned ${stats.tweetsScanned} tweets, found ${stats.notesFound} Community Notes`);
  };

  const writeNote = async () => {
    if (!CONFIG.tweetUrl) {
      console.log('❌ No tweetUrl provided in CONFIG.tweetUrl');
      return;
    }
    if (!CONFIG.noteText) {
      console.log('❌ No noteText provided in CONFIG.noteText');
      return;
    }

    // Navigate to the tweet
    console.log(`🔄 Navigating to tweet: ${CONFIG.tweetUrl}`);
    if (!CONFIG.dryRun && window.location.href !== CONFIG.tweetUrl) {
      window.location.href = CONFIG.tweetUrl;
      return; // Page will reload
    }

    await sleep(CONFIG.navigationDelay);

    // Look for the "Write a note" option
    // First try the caret/more menu on the tweet
    const tweet = await waitForSelector(SEL.tweet, 5000);
    if (!tweet) {
      console.log('❌ Could not find the tweet');
      return;
    }

    let writeBtn = tweet.querySelector(SEL.writeNote);

    if (!writeBtn) {
      // Try the caret menu
      const caretBtn = tweet.querySelector(SEL.caret);
      if (caretBtn && !CONFIG.dryRun) {
        caretBtn.click();
        await sleep(CONFIG.actionDelay);

        const menuItems = $$('[role="menuitem"]');
        writeBtn = menuItems.find(item =>
          item.textContent.toLowerCase().includes('note') ||
          item.textContent.toLowerCase().includes('community note')
        );
      }
    }

    if (!writeBtn) {
      console.log('❌ Could not find "Write a note" option');
      console.log('💡 Make sure you are enrolled in Community Notes at x.com/i/communitynotes');
      return;
    }

    if (!CONFIG.dryRun) {
      writeBtn.click();
      await sleep(CONFIG.navigationDelay);
    }

    // Select classification
    console.log(`📋 Classification: ${CONFIG.noteClassification}`);
    const classificationMap = {
      misleading: 'misinformed',
      not_misleading: 'not_misleading',
      might_be_misleading: 'might_be_misleading',
    };

    const classLabels = $$('[role="radio"], [role="option"], input[type="radio"]');
    for (const label of classLabels) {
      const text = label.textContent?.toLowerCase() || label.value?.toLowerCase() || '';
      const target = (classificationMap[CONFIG.noteClassification] || CONFIG.noteClassification).toLowerCase();
      if (text.includes(target)) {
        if (!CONFIG.dryRun) {
          label.click();
          await sleep(CONFIG.actionDelay);
        }
        break;
      }
    }

    // Type the note
    console.log('✍️ Writing note...');
    const noteInput = document.querySelector('textarea, [contenteditable="true"], [data-testid="noteTextarea"]');
    if (noteInput && !CONFIG.dryRun) {
      await typeText(noteInput, CONFIG.noteText);
      await sleep(1000);
    }

    // Submit
    const submitBtn = document.querySelector('[data-testid="submitNote"], button[type="submit"]');
    if (submitBtn) {
      if (!CONFIG.dryRun) {
        submitBtn.click();
        await sleep(CONFIG.actionDelay);
      }
      stats.noteWritten = true;
      console.log('✅ Community Note submitted');
    } else {
      console.log('⚠️ Could not find submit button — note may need manual submission');
    }
  };

  const rateNotes = async () => {
    console.log(`🔄 Rating Community Notes as ${CONFIG.rateAsHelpful ? 'helpful' : 'not helpful'}...`);

    const processedTweets = new Set();
    let scrollAttempts = 0;

    while (scrollAttempts < CONFIG.maxScrollAttempts && !aborted) {
      const tweets = $$(SEL.tweet);

      for (const tweet of tweets) {
        if (aborted) break;

        const info = extractTweetInfo(tweet);
        if (!info.link || processedTweets.has(info.link)) continue;
        processedTweets.add(info.link);

        const note = tweet.querySelector(SEL.communityNote);
        if (!note) continue;

        stats.notesFound++;

        // Look for rate buttons
        const rateBtn = note.querySelector(SEL.rateNote) ||
                        note.querySelector('[aria-label*="ate"], [aria-label*="elpful"]');

        if (rateBtn) {
          console.log(`📝 Rating note on tweet by ${info.author}...`);

          if (!CONFIG.dryRun) {
            rateBtn.click();
            await sleep(CONFIG.actionDelay);

            // Select helpful or not helpful
            const options = $$('[role="radio"], [role="option"], button');
            const targetText = CONFIG.rateAsHelpful ? 'helpful' : 'not helpful';
            const targetOption = options.find(opt =>
              opt.textContent?.toLowerCase()?.includes(targetText)
            );

            if (targetOption) {
              targetOption.click();
              await sleep(CONFIG.actionDelay);

              // Submit rating
              const submitBtn = document.querySelector('[data-testid="submitRating"], button[type="submit"]');
              if (submitBtn) {
                submitBtn.click();
                await sleep(CONFIG.actionDelay);
              }
            }
          }

          stats.notesRated++;
          console.log(`  ✅ Rated as ${CONFIG.rateAsHelpful ? 'helpful' : 'not helpful'} (${stats.notesRated})`);
        }
      }

      window.scrollBy(0, 600);
      await sleep(CONFIG.scrollDelay);
      scrollAttempts++;
    }

    console.log(`✅ Rated ${stats.notesRated} Community Notes`);
  };

  const browseNotedTweets = async () => {
    console.log('🔍 Browsing tweets with Community Notes...');

    // Try navigating to Community Notes hub
    if (!CONFIG.dryRun) {
      console.log('💡 Tip: Visit x.com/i/communitynotes for the full Community Notes dashboard');
    }

    // Scan timeline for noted tweets
    await viewNotes();

    // Export results
    if (stats.notesViewed.length > 0) {
      console.log('');
      console.log('📋 Noted Tweets Export:');
      console.log(JSON.stringify(stats.notesViewed, null, 2));
    }
  };

  const run = async () => {
    const W = 60;
    console.log('╔' + '═'.repeat(W) + '╗');
    console.log('║  📝 COMMUNITY NOTES' + ' '.repeat(W - 22) + '║');
    console.log('║  by nichxbt — v1.0' + ' '.repeat(W - 21) + '║');
    console.log('╚' + '═'.repeat(W) + '╝');

    if (CONFIG.dryRun) {
      console.log('⚠️ DRY RUN MODE — set CONFIG.dryRun = false to actually act');
    }

    console.log(`📋 Action: ${CONFIG.action}`);

    const sessionKey = 'xactions_communityNotes';
    sessionStorage.setItem(sessionKey, JSON.stringify({ status: 'running', ...stats }));

    const actions = {
      view: viewNotes,
      write: writeNote,
      rate: rateNotes,
      browse: browseNotedTweets,
    };

    if (!actions[CONFIG.action]) {
      console.log(`❌ Unknown action: "${CONFIG.action}"`);
      console.log(`💡 Valid actions: ${Object.keys(actions).join(', ')}`);
      return;
    }

    await actions[CONFIG.action]();

    if (aborted) console.log('🛑 Aborted by user');

    // Final summary
    console.log('');
    console.log('╔' + '═'.repeat(W) + '╗');
    console.log('║  📊 COMMUNITY NOTES SUMMARY' + ' '.repeat(W - 30) + '║');
    console.log('╚' + '═'.repeat(W) + '╝');
    console.log(`🔧 Action: ${CONFIG.action}`);
    console.log(`📝 Notes found: ${stats.notesFound}`);
    if (stats.noteWritten) console.log('✍️ Note written: ✅');
    if (stats.notesRated > 0) console.log(`⭐ Notes rated: ${stats.notesRated}`);
    console.log(`📄 Tweets scanned: ${stats.tweetsScanned}`);
    console.log(`⏱️ Duration: ${((Date.now() - stats.startTime) / 1000).toFixed(1)}s`);

    sessionStorage.setItem(sessionKey, JSON.stringify({ status: 'complete', ...stats }));
  };

  run();
})();

⚡ More XActions Scripts

Browse 300+ free browser scripts for X/Twitter automation. No API keys, no fees.

Browse All Scripts