👥 Group Direct Messages

Messaging src
v1.0.0 Updated: 2026-03-30 240 lines by @nichxbt

Create group DM conversations and send messages

How to Use

  1. Go to: https://x.com/messages
  2. Open DevTools Console (F12)
  3. Edit CONFIG below (recipients & message)
  4. Paste and run

Runtime Controls

window.XActions.abort()   — stop the script
window.XActions.status()  — check progress

Configuration Options

OptionDefaultDescription
message'Hey everyone! 👋'Message to send after creating the group
searchDelay2000Delay after typing each username
selectDelay1500Delay after selecting each user
actionDelay2000Delay between major actions
typeCharDelay50Delay between keystrokes when typing
dryRuntrueSet to false to actually send

Default Configuration

const CONFIG = {
    // ── Recipients ───────────────────────────────────────────
    recipients: ['user1', 'user2', 'user3'], // Usernames (without @) to add to group
    message: 'Hey everyone! 👋',              // Message to send after creating the group

    // ── Timing ───────────────────────────────────────────────
    searchDelay: 2000,       // Delay after typing each username
    selectDelay: 1500,       // Delay after selecting each user
    actionDelay: 2000,       // Delay between major actions
    typeCharDelay: 50,       // Delay between keystrokes when typing

    // ── Safety ───────────────────────────────────────────────
    dryRun: true,            // Set to false to actually send
  };

Full Script

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

/**
 * ============================================================
 * 💬 Group Direct Messages — Production Grade
 * ============================================================
 *
 * @name        groupDM.js
 * @description Create group DM conversations and send messages
 *              to multiple users at once on X/Twitter.
 * @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/messages
 * 2. Open DevTools Console (F12)
 * 3. Edit CONFIG below (recipients & message)
 * 4. Paste and run
 *
 * 🎮 CONTROLS:
 *   window.XActions.abort()   — stop the script
 *   window.XActions.status()  — check progress
 * ============================================================
 */
// by nichxbt
(() => {
  'use strict';

  const CONFIG = {
    // ── Recipients ───────────────────────────────────────────
    recipients: ['user1', 'user2', 'user3'], // Usernames (without @) to add to group
    message: 'Hey everyone! 👋',              // Message to send after creating the group

    // ── Timing ───────────────────────────────────────────────
    searchDelay: 2000,       // Delay after typing each username
    selectDelay: 1500,       // Delay after selecting each user
    actionDelay: 2000,       // Delay between major actions
    typeCharDelay: 50,       // Delay between keystrokes when typing

    // ── Safety ───────────────────────────────────────────────
    dryRun: true,            // Set to false to actually send
  };

  const SEL = {
    newDM:          '[data-testid="NewDM_Button"]',
    searchPeople:   '[data-testid="searchPeople"]',
    typeaheadUser:  '[data-testid="TypeaheadUser"]',
    nextButton:     '[data-testid="nextButton"]',
    composerInput:  '[data-testid="dmComposerTextInput"]',
    sendButton:     '[data-testid="dmComposerSendButton"]',
  };

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

  const stats = {
    recipientsAdded: 0,
    recipientsFailed: [],
    messageSent: false,
    startTime: Date.now(),
  };

  window.XActions = {
    abort()  { aborted = true; console.log('🛑 Aborting...'); },
    status() {
      const el = ((Date.now() - stats.startTime) / 1000).toFixed(0);
      console.log(`📊 Added: ${stats.recipientsAdded}/${CONFIG.recipients.length} | Message sent: ${stats.messageSent} | ${el}s`);
    },
  };

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

  const clearInput = (element) => {
    element.focus();
    element.value = '';
    element.textContent = '';
    element.dispatchEvent(new Event('input', { bubbles: true }));
  };

  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 run = async () => {
    const W = 60;
    console.log('╔' + '═'.repeat(W) + '╗');
    console.log('║  💬 GROUP DIRECT MESSAGES' + ' '.repeat(W - 27) + '║');
    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 send');
    }

    if (CONFIG.recipients.length < 2) {
      console.log('❌ Need at least 2 recipients for a group DM');
      return;
    }

    console.log(`📋 Recipients: ${CONFIG.recipients.join(', ')}`);
    console.log(`💬 Message: "${CONFIG.message}"`);

    // Save state to sessionStorage
    const sessionKey = 'xactions_groupDM';
    sessionStorage.setItem(sessionKey, JSON.stringify({ status: 'running', ...stats }));

    // Step 1: Click New DM button
    console.log('🔄 Opening new message dialog...');
    const newDMBtn = await waitForSelector(SEL.newDM);
    if (!newDMBtn) {
      console.log('❌ Could not find New DM button. Make sure you are on x.com/messages');
      return;
    }

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

    // Step 2: Search and add each recipient
    for (const username of CONFIG.recipients) {
      if (aborted) break;

      console.log(`🔍 Searching for @${username}...`);

      const searchInput = await waitForSelector(SEL.searchPeople);
      if (!searchInput) {
        console.log(`❌ Could not find search input for @${username}`);
        stats.recipientsFailed.push(username);
        continue;
      }

      if (!CONFIG.dryRun) {
        clearInput(searchInput);
        await sleep(500);
        await typeText(searchInput, username);
        await sleep(CONFIG.searchDelay);

        // Select the first matching user
        const userResult = await waitForSelector(SEL.typeaheadUser);
        if (!userResult) {
          console.log(`⚠️ Could not find @${username} in search results`);
          stats.recipientsFailed.push(username);
          continue;
        }

        userResult.click();
        await sleep(CONFIG.selectDelay);
      }

      stats.recipientsAdded++;
      console.log(`✅ Added @${username} (${stats.recipientsAdded}/${CONFIG.recipients.length})`);
    }

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

    if (stats.recipientsAdded < 2) {
      console.log('❌ Need at least 2 recipients added to create a group. Only got ' + stats.recipientsAdded);
      return;
    }

    // Step 3: Click Next to create the conversation
    console.log('🔄 Creating group conversation...');
    if (!CONFIG.dryRun) {
      const nextBtn = await waitForSelector(SEL.nextButton);
      if (!nextBtn) {
        console.log('❌ Could not find Next button');
        return;
      }
      nextBtn.click();
      await sleep(CONFIG.actionDelay);
    }

    // Step 4: Type and send the message
    if (CONFIG.message) {
      console.log('✍️ Typing message...');
      if (!CONFIG.dryRun) {
        const composerInput = await waitForSelector(SEL.composerInput);
        if (!composerInput) {
          console.log('❌ Could not find message composer');
          return;
        }

        await typeText(composerInput, CONFIG.message);
        await sleep(1000);

        const sendBtn = await waitForSelector(SEL.sendButton);
        if (!sendBtn) {
          console.log('❌ Could not find send button');
          return;
        }
        sendBtn.click();
        await sleep(CONFIG.actionDelay);
      }

      stats.messageSent = true;
      console.log('✅ Message sent!');
    }

    // Final summary
    console.log('');
    console.log('╔' + '═'.repeat(W) + '╗');
    console.log('║  📊 GROUP DM SUMMARY' + ' '.repeat(W - 22) + '║');
    console.log('╚' + '═'.repeat(W) + '╝');
    console.log(`✅ Recipients added: ${stats.recipientsAdded}`);
    if (stats.recipientsFailed.length > 0) {
      console.log(`⚠️ Failed: ${stats.recipientsFailed.join(', ')}`);
    }
    console.log(`💬 Message sent: ${stats.messageSent}`);
    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