⚡ XActions
⚙️ Browser Automation

Advanced Automation Techniques

Chaining scripts, persistent workflows, debugging strategies, and power-user patterns.


Table of Contents


Chaining Scripts Together

Scripts coexist in the same browser tab because they all share window.XActions. The order you paste them determines what's available.

Pattern 1: Growth + Protection + Tracking

1. Paste core.js                    → window.XActions.Core ready
2. Paste sessionLogger.js           → Starts logging all actions
3. Paste protectActiveUsers.js      → Scans your posts, builds whitelist
4. Paste growthSuite.js             → Growth automation runs

What happens: sessionLogger records everything. protectActiveUsers writes to xactions_protected_users. smartUnfollow (inside growthSuite) skips protected users. The session log captures the full audit trail.

Pattern 2: Research → Follow → Engage

1. Paste core.js
2. Paste actions.js                 → Full XActions.* API
3. Navigate to a viral tweet in your niche
4. Paste followEngagers.js          → Follow the likers
5. Paste autoLiker.js               → Like related content

What happens: followEngagers builds a list of engaged users. autoLiker independently likes matching content on the page. Both track their actions separately.

Pattern 3: Control Panel + Any Script

1. Paste core.js
2. Paste controlPanel.js            → Floating UI appears
3. Select an automation from the dropdown
4. Configure via the panel's inputs
5. Click Start

What happens: The control panel replaces individual script configuration. It provides visual controls for start/pause/resume and real-time progress tracking.

Pattern 4: Actions Library Interactive Use

1. Paste core.js
2. Paste actions.js
3. Run commands interactively:
// Interactive exploration
await XActions.search.advanced({
  from: 'elonmusk',
  minFaves: 1000,
  since: '2025-01-01',
});

// Get results and like them
const tweets = XActions.search.getResults();
for (const tweet of tweets.slice(0, 5)) {
  await XActions.engage.like(tweet);
  await XActions.Core?.sleep(2000); // Access Core through closure
}

// Export your bookmarks
const bookmarks = await XActions.utils.exportBookmarks(100);
console.table(bookmarks);

Sustainable Growth Cycles

The Weekly Cycle

Day Action Script
Mon-Fri Follow 20 targeted users keywordFollow.js
Mon-Fri Like 30 posts in your niche autoLiker.js
Saturday Scan posts for engaged users protectActiveUsers.js
Sunday Unfollow non-followers from 7+ days ago smartUnfollow.js

Setting Up the Cycle

Monday-Friday:

// keywordFollow.js config
const OPTIONS = {
  KEYWORDS: ['your niche keyword 1', 'your niche keyword 2'],
  MAX_FOLLOWS_PER_KEYWORD: 10,
  MAX_FOLLOWS_TOTAL: 20,
  MIN_FOLLOWERS: 100,
  MAX_FOLLOWERS: 50000,
  MUST_HAVE_BIO: true,
};

Every follow is recorded with a timestamp in xactions_followed_users.

Saturday:

// protectActiveUsers.js config
const CONFIG = {
  POSTS_TO_SCAN: 20,   // Check your last 20 posts
};

Builds list of users who engage with your content.

Sunday:

// smartUnfollow.js config
const OPTIONS = {
  DAYS_TO_WAIT: 7,       // 1 week grace period
  MAX_UNFOLLOWS: 50,
  DRY_RUN: true,         // Run dry first to preview!
  ONLY_TRACKED: true,    // Only unfollow users we tracked from keywordFollow
  WHITELIST: [],
};

Growth Math

If you follow 20 users/day and ~40% follow back:

  • Week 1: +100 follows → ~40 new followers
  • Week 2: +100 more → ~40 more followers, unfollow ~60 non-followers from Week 1
  • Month 1: ~160 new followers, following count stays stable

State Management Across Sessions

How Data Persists

Storage Survives Refresh Survives Tab Close Used For
localStorage (via Core.storage) Tracked users, liked tweets, rate limits
sessionStorage Navigation state, processed pages
In-memory variables Current session counters

Viewing All Stored Data

// List all XActions keys
window.XActions.Core.storage.list();

// View specific data
window.XActions.Core.storage.get('followed_users');
window.XActions.Core.storage.get('liked_tweets');
window.XActions.Core.storage.get('my_followers');
window.XActions.Core.storage.get('protected_users');
window.XActions.Core.storage.get('session_log');

// View rate limit status
window.XActions.Core.rateLimit.getRemaining('follow', 100, 'day');
window.XActions.Core.rateLimit.getRemaining('like', 200, 'day');

Exporting Data

// Export all XActions data as JSON
const allData = {};
window.XActions.Core.storage.list().forEach(key => {
  allData[key] = window.XActions.Core.storage.get(key);
});
console.log(JSON.stringify(allData, null, 2));

// Copy to clipboard
copy(JSON.stringify(allData, null, 2));

Importing Data (Restore from Backup)

const backup = { /* your exported data */ };
Object.entries(backup).forEach(([key, value]) => {
  window.XActions.Core.storage.set(key, value);
});

Clearing Data

// Clear specific key
window.XActions.Core.storage.remove('followed_users');

// Clear all XActions data
window.XActions.Core.storage.clear();

// Nuclear option — clear ALL X data from localStorage
XActions.utils.clearXData(); // Requires actions.js loaded

Debugging Techniques

Enable Verbose Logging

window.XActions.Core.CONFIG.DEBUG = true;

Check Extraction Quality

After running any script that extracts user data:

window.XActions.Core.extractionStats.report();

This shows which extraction strategies are working:

📊 Extraction Strategy Report:
  bio: 45 extractions
    testid: 40 (88.9%) ████████████████
    dir-auto: 5 (11.1%) ██

If testid drops below 50%, X has changed their DOM. Check dom-selectors.md for updates.

Visual DOM Inspector

// After loading actions.js:
XActions.utils.devMode();

This outlines every data-testid element in red with tooltip labels. Hover over elements to see their selector names.

Find All Selectors on Current Page

XActions.utils.getAllSelectors();
// Returns sorted array of all data-testid values

Check Rate Limit Status

['follow', 'like', 'unfollow', 'comment'].forEach(action => {
  const hourly = window.XActions.Core.rateLimit.getRemaining(action, 50, 'hour');
  const daily = window.XActions.Core.rateLimit.getRemaining(action, 200, 'day');
  console.log(`${action}: ${hourly} left this hour, ${daily} left today`);
});

Test DOM Selection Without Acting

const { SELECTORS } = window.XActions.Core;

// Count tweets on page
document.querySelectorAll(SELECTORS.tweet).length;

// Check if follow buttons exist
document.querySelectorAll(SELECTORS.followButton).length;

// Test user extraction on first cell
const cell = document.querySelector(SELECTORS.userCell);
if (cell) console.log(window.XActions.Core.extractUserFromCell(cell));

DOM Discovery & Selector Updates

X/Twitter changes their DOM frequently. Here's how to find new selectors:

Method 1: devMode()

XActions.utils.devMode();
// Now hover over elements — each data-testid is shown as a tooltip

Method 2: Element Inspector

  1. Right-click any element → Inspect
  2. Look for data-testid attribute in the element tree
  3. That's your selector: [data-testid="the-value"]

Method 3: JavaScript Discovery

// Find all data-testid values on the page
const selectors = new Set();
document.querySelectorAll('[data-testid]').forEach(el => {
  selectors.add(el.getAttribute('data-testid'));
});
console.log([...selectors].sort());

Method 4: Monitor New Selectors

// Watch for new data-testid elements appearing
const observer = new MutationObserver(mutations => {
  for (const mutation of mutations) {
    for (const node of mutation.addedNodes) {
      if (node.nodeType === 1) {
        const testId = node.getAttribute?.('data-testid');
        if (testId) console.log('New element:', testId);
        node.querySelectorAll?.('[data-testid]').forEach(el => {
          console.log('New element:', el.getAttribute('data-testid'));
        });
      }
    }
  }
});
observer.observe(document.body, { childList: true, subtree: true });

Custom Script Patterns

Template: Custom Automation Script

(() => {
  if (!window.XActions?.Core) {
    console.error('❌ Core module not loaded! Paste core.js first.');
    return;
  }

  const { log, sleep, randomDelay, scrollBy, clickElement,
          waitForElement, storage, rateLimit, SELECTORS } = window.XActions.Core;

  // ============================================
  // CONFIGURATION
  // ============================================
  const OPTIONS = {
    MAX_ACTIONS: 10,
    MIN_DELAY: 2000,
    MAX_DELAY: 5000,
  };

  // ============================================
  // STATE
  // ============================================
  let actionCount = 0;
  let isRunning = true;
  const processed = new Set(storage.get('my_script_processed') || []);

  // ============================================
  // MAIN LOGIC
  // ============================================
  const processItem = async (element) => {
    // Your logic here
    actionCount++;
    rateLimit.increment('my_action', 'hour');
    log(`Action #${actionCount}`, 'success');
  };

  const run = async () => {
    log('🚀 Starting custom automation...', 'info');

    while (isRunning && actionCount < OPTIONS.MAX_ACTIONS) {
      // Check rate limits
      if (!rateLimit.check('my_action', 50, 'hour')) {
        log('Rate limit reached', 'warning');
        break;
      }

      // Find elements to process
      const elements = document.querySelectorAll(SELECTORS.tweet);
      for (const el of elements) {
        if (!isRunning || actionCount >= OPTIONS.MAX_ACTIONS) break;
        await processItem(el);
        await randomDelay(OPTIONS.MIN_DELAY, OPTIONS.MAX_DELAY);
      }

      // Scroll for more
      scrollBy(600);
      await sleep(2000);
    }

    // Save state
    storage.set('my_script_processed', Array.from(processed));
    log(`✅ Done! ${actionCount} actions performed.`, 'success');
  };

  // Stop function
  window.stopMyScript = () => {
    isRunning = false;
    log('Stopping...', 'warning');
  };

  run();
})();

Pattern: Scroll & Collect (No Actions)

const collectData = async () => {
  const data = [];
  let lastHeight = 0;

  while (data.length < 100) {
    const items = document.querySelectorAll('[data-testid="tweet"]');
    items.forEach(item => {
      const link = item.querySelector('a[href*="/status/"]')?.href;
      const text = item.querySelector('[data-testid="tweetText"]')?.textContent;
      if (link && !data.find(d => d.link === link)) {
        data.push({ link, text: text?.substring(0, 100) });
      }
    });

    window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' });
    await window.XActions.Core.sleep(2000);

    if (document.body.scrollHeight === lastHeight) break;
    lastHeight = document.body.scrollHeight;
  }

  return data;
};

const results = await collectData();
console.table(results);

Performance Optimization

Delay Tuning

Risk Level Min Delay Max Delay Actions/Hour
Conservative 5000ms 10000ms ~25
Moderate 2000ms 5000ms ~50
Aggressive 1000ms 2000ms ~100+

Recommendation: Start conservative. Only increase speed after testing for weeks without issues.

Memory Management

Long-running scripts (algorithmTrainer, autoCommenter with monitoring) can accumulate data:

// Check memory of tracked sets
const followed = window.XActions.Core.storage.get('followed_users');
console.log(`Tracking ${Object.keys(followed || {}).length} users`);

// Prune old entries (older than 30 days)
const cutoff = Date.now() - (30 * 24 * 60 * 60 * 1000);
for (const [user, data] of Object.entries(followed)) {
  if (data.followedAt < cutoff) delete followed[user];
}
window.XActions.Core.storage.set('followed_users', followed);

Account Safety Strategies

The 80/20 Rule

Keep your automation-to-manual ratio at 80% manual, 20% automated (by volume). Use automation for the tedious parts (finding users, scrolling) and do genuine engagement manually.

Warm-Up Period

New accounts should not run automation immediately. Use the algorithm scripts first:

Week 1-2: algorithmTrainer.js only (browsing, not acting)
Week 3:   Add autoLiker.js with very low limits (5-10/day)
Week 4:   Add keywordFollow.js with very low limits (5-10/day)
Month 2+: Gradually increase limits

Signs You're Being Rate Limited

  • Actions start failing silently
  • Follow buttons don't respond
  • You see "You are unable to perform this action" messages
  • Toast notifications about limits appear

What to do:

  1. Stop all automation immediately
  2. Wait at least 1 hour (24 hours if severe)
  3. Reduce your limits by 50%
  4. Increase delays between actions

What NOT to Do

  • Don't run the same script across multiple browser tabs
  • Don't exceed 100 follows/day or 200 likes/day
  • Don't comment the same text repeatedly
  • Don't automate 24/7 without breaks
  • Don't run automation on accounts less than 1 month old

⚡ Free and open source

No API keys, no monthly fees, no signup. Star the repo if it saved you a subscription.

View on GitHub