โ ๏ธ Prerequisites
These automation scripts require core.js to be loaded first. The core module provides shared utilities like rate limiting, storage, and selectors. Paste core.js before running any automation script.
โค๏ธ Auto Liker
Automatically like tweets in your timeline or on any profile. Filter by keywords, users, or like everything.
Step 1: Go to your timeline or any profile
Navigate to x.com/home or any user's profile page.
Step 2: Open Developer Console
Press F12 (Windows) or Cmd+Option+J (Mac) and click the Console tab.
Step 3: First paste core.js (required)
// XActions Core Module - Required for automation scripts
// https://github.com/nirholas/XActions
window.XActions = window.XActions || {};
window.XActions.Core = (() => {
const SELECTORS = {
tweet: 'article[data-testid="tweet"]',
likeButton: '[data-testid="like"]',
unlikeButton: '[data-testid="unlike"]',
retweetButton: '[data-testid="retweet"]',
replyButton: '[data-testid="reply"]',
tweetText: '[data-testid="tweetText"]',
userCell: '[data-testid="UserCell"]',
};
const log = (msg, type = 'info') => {
const icons = { info: 'โน๏ธ', success: 'โ
', warning: 'โ ๏ธ', error: 'โ', action: '๐ฏ' };
console.log(`${icons[type] || 'โข'} [XActions] ${msg}`);
};
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
const randomDelay = (min = 1000, max = 3000) => sleep(min + Math.random() * (max - min));
const scrollBy = (px = 500) => window.scrollBy({ top: px, behavior: 'smooth' });
const scrollToTop = () => window.scrollTo({ top: 0, behavior: 'smooth' });
const clickElement = async (el) => {
if (!el) return false;
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
await sleep(300);
el.click();
return true;
};
const waitForElement = (selector, timeout = 5000) => {
return new Promise((resolve) => {
const el = document.querySelector(selector);
if (el) return resolve(el);
const observer = new MutationObserver(() => {
const el = document.querySelector(selector);
if (el) { observer.disconnect(); resolve(el); }
});
observer.observe(document.body, { childList: true, subtree: true });
setTimeout(() => { observer.disconnect(); resolve(null); }, timeout);
});
};
const storage = {
get: (key) => { try { return JSON.parse(localStorage.getItem(`xactions_${key}`)); } catch { return null; } },
set: (key, val) => localStorage.setItem(`xactions_${key}`, JSON.stringify(val)),
remove: (key) => localStorage.removeItem(`xactions_${key}`),
};
const rateLimit = {
_counts: {},
check: (action, limit, period) => {
const key = `${action}_${period}`;
const count = rateLimit._counts[key] || 0;
return count < limit;
},
increment: (action, period) => {
const key = `${action}_${period}`;
rateLimit._counts[key] = (rateLimit._counts[key] || 0) + 1;
},
};
log('Core module loaded!', 'success');
return { SELECTORS, log, sleep, randomDelay, scrollBy, scrollToTop, clickElement, waitForElement, storage, rateLimit };
})();
Step 4: Then paste the Auto Liker script
// XActions Auto Liker - by nichxbt
// https://github.com/nirholas/XActions
// Requires core.js to be loaded first!
(() => {
if (!window.XActions?.Core) {
console.error('โ Core module not loaded! Paste core.js first.');
return;
}
const { log, sleep, randomDelay, scrollBy, clickElement, storage, SELECTORS } = window.XActions.Core;
// ============================================
// CONFIGURATION - Edit these options!
// ============================================
const OPTIONS = {
LIKE_ALL: false, // true = like everything, false = use filters
KEYWORDS: ['web3', 'crypto', 'AI'], // Only like posts with these words (if LIKE_ALL is false)
FROM_USERS: [], // Only like from these users (empty = all users)
MAX_LIKES: 20, // Stop after this many likes
MIN_DELAY: 2000, // Minimum delay between likes (ms)
MAX_DELAY: 5000, // Maximum delay between likes (ms)
SKIP_REPLIES: true, // Skip reply tweets
};
let likeCount = 0;
let scrollCount = 0;
const likedIds = new Set(storage.get('liked_tweets') || []);
const getTweetId = (tweet) => {
const link = tweet.querySelector('a[href*="/status/"]');
const match = link?.href?.match(/status\/(\d+)/);
return match ? match[1] : null;
};
const matchesKeywords = (text) => {
if (OPTIONS.LIKE_ALL) return true;
if (OPTIONS.KEYWORDS.length === 0) return true;
const lower = text.toLowerCase();
return OPTIONS.KEYWORDS.some(kw => lower.includes(kw.toLowerCase()));
};
const isAlreadyLiked = (tweet) => !!tweet.querySelector(SELECTORS.unlikeButton);
const likeTweet = async (tweet) => {
const btn = tweet.querySelector(SELECTORS.likeButton);
if (!btn) return false;
await clickElement(btn);
likeCount++;
const id = getTweetId(tweet);
if (id) { likedIds.add(id); storage.set('liked_tweets', [...likedIds]); }
log(`Liked tweet #${likeCount}`, 'success');
return true;
};
const run = async () => {
log(`Starting Auto Liker (max: ${OPTIONS.MAX_LIKES} likes)`, 'info');
while (likeCount < OPTIONS.MAX_LIKES && scrollCount < 50) {
const tweets = document.querySelectorAll(SELECTORS.tweet);
for (const tweet of tweets) {
if (likeCount >= OPTIONS.MAX_LIKES) break;
const id = getTweetId(tweet);
if (id && likedIds.has(id)) continue;
if (isAlreadyLiked(tweet)) continue;
const text = tweet.querySelector(SELECTORS.tweetText)?.textContent || '';
if (!matchesKeywords(text)) continue;
await likeTweet(tweet);
await sleep(OPTIONS.MIN_DELAY + Math.random() * (OPTIONS.MAX_DELAY - OPTIONS.MIN_DELAY));
}
scrollBy(600);
scrollCount++;
await sleep(2000);
}
log(`Done! Liked ${likeCount} tweets.`, 'success');
};
run();
})();
โ ๏ธ Important Notes
- Edit the
OPTIONSobject to customize behavior - Set
KEYWORDSto only like relevant tweets - Keep delays reasonable (2-5 seconds) to avoid rate limits
- Start with small
MAX_LIKESvalues to test
๐ฌ Auto Commenter
Monitor a user's profile and automatically reply to their new posts. Great for engagement and building relationships.
Step 1: Go to the target user's profile
Navigate to x.com/USERNAME (replace with the account you want to engage with).
Step 2: Paste core.js first (same as above)
If you haven't already, paste the core.js script from the Auto Liker section.
Step 3: Paste the Auto Commenter script
// XActions Auto Commenter - by nichxbt
// https://github.com/nirholas/XActions
// Monitors a profile and auto-comments on new posts
// Requires core.js to be loaded first!
(() => {
if (!window.XActions?.Core) {
console.error('โ Core module not loaded! Paste core.js first.');
return;
}
const { log, sleep, clickElement, waitForElement, storage, SELECTORS } = window.XActions.Core;
// ============================================
// CONFIGURATION - Customize your comments!
// ============================================
const OPTIONS = {
// Random comments to choose from
COMMENTS: [
'๐ฅ',
'Great point!',
'This is so true ๐',
'Interesting take!',
'Love this perspective',
'๐ฏ',
],
CHECK_INTERVAL: 60, // Check for new posts every X seconds
MAX_COMMENTS: 5, // Max comments per session
ONLY_ORIGINAL: true, // Skip replies and retweets
};
let commentCount = 0;
let isRunning = true;
const commented = new Set(storage.get('commented_tweets') || []);
const getUsername = () => window.location.pathname.split('/')[1];
const getRandomComment = () => OPTIONS.COMMENTS[Math.floor(Math.random() * OPTIONS.COMMENTS.length)];
const getTweetId = (tweet) => {
const link = tweet.querySelector('a[href*="/status/"]');
const match = link?.href?.match(/status\/(\d+)/);
return match ? match[1] : null;
};
const postComment = async (tweet) => {
const id = getTweetId(tweet);
if (!id || commented.has(id)) return false;
// Click reply button
const replyBtn = tweet.querySelector(SELECTORS.replyButton);
if (!replyBtn) return false;
await clickElement(replyBtn);
await sleep(1000);
// Wait for reply input
const input = await waitForElement('[data-testid="tweetTextarea_0"]', 5000);
if (!input) {
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
return false;
}
// Type comment
input.focus();
await sleep(300);
document.execCommand('insertText', false, getRandomComment());
await sleep(500);
// Click post
const postBtn = await waitForElement('[data-testid="tweetButton"]', 3000);
if (postBtn) {
await clickElement(postBtn);
commentCount++;
commented.add(id);
storage.set('commented_tweets', [...commented]);
log(`Posted comment #${commentCount}`, 'success');
return true;
}
return false;
};
const checkForPosts = async () => {
if (!isRunning || commentCount >= OPTIONS.MAX_COMMENTS) {
log(`Session complete. Posted ${commentCount} comments.`, 'success');
return;
}
log(`Checking for new posts from @${getUsername()}...`, 'info');
const tweets = document.querySelectorAll(SELECTORS.tweet);
for (const tweet of tweets) {
if (commentCount >= OPTIONS.MAX_COMMENTS) break;
const id = getTweetId(tweet);
if (commented.has(id)) continue;
// Skip retweets if configured
if (OPTIONS.ONLY_ORIGINAL && tweet.textContent?.includes('reposted')) continue;
await postComment(tweet);
await sleep(3000);
}
// Schedule next check
log(`Next check in ${OPTIONS.CHECK_INTERVAL} seconds...`, 'info');
setTimeout(checkForPosts, OPTIONS.CHECK_INTERVAL * 1000);
};
// Stop function
window.stopAutoComment = () => { isRunning = false; log('Stopping...', 'warning'); };
log(`Auto Commenter started for @${getUsername()}`, 'info');
log('Type stopAutoComment() to stop', 'info');
checkForPosts();
})();
โ ๏ธ Use Responsibly
- Customize comments to be genuine and relevant
- Don't spam - use reasonable limits
- Type
stopAutoComment()in console to stop - Spammy behavior can get your account limited
๐ฅ Follow Engagers
Find and follow users who liked or retweeted specific posts. Great for growing your network with engaged users.
Step 1: Go to any tweet
Navigate to a popular tweet: x.com/user/status/123456
Step 2: Paste core.js first
If you haven't already, paste the core.js script.
Step 3: Paste the Follow Engagers script
// XActions Follow Engagers - by nichxbt
// https://github.com/nirholas/XActions
// Follow users who liked/retweeted a post
// Requires core.js to be loaded first!
(() => {
if (!window.XActions?.Core) {
console.error('โ Core module not loaded! Paste core.js first.');
return;
}
const { log, sleep, scrollBy, clickElement, storage, SELECTORS } = window.XActions.Core;
// ============================================
// CONFIGURATION
// ============================================
const CONFIG = {
MODE: 'likers', // 'likers' or 'retweeters'
MAX_FOLLOWS: 20, // Max follows per session
DELAY_BETWEEN: 3000, // Delay between follows (ms)
SKIP_VERIFIED: false, // Skip verified accounts
SKIP_PROTECTED: true, // Skip private accounts
};
let followCount = 0;
const followed = new Set(storage.get('engager_followed') || []);
const extractPostId = () => {
const match = window.location.href.match(/status\/(\d+)/);
return match ? match[1] : null;
};
const followUser = async (cell) => {
const followBtn = cell.querySelector('[data-testid$="-follow"]');
if (!followBtn) return false;
// Check if already following
if (followBtn.textContent?.includes('Following')) return false;
// Get username
const link = cell.querySelector('a[href^="/"]');
const username = link?.getAttribute('href')?.replace('/', '') || 'unknown';
if (followed.has(username)) return false;
await clickElement(followBtn);
followCount++;
followed.add(username);
storage.set('engager_followed', [...followed]);
log(`Followed @${username} (#${followCount})`, 'success');
return true;
};
const run = async () => {
const postId = extractPostId();
if (!postId) {
log('Please navigate to a tweet first!', 'error');
return;
}
// Navigate to likers/retweeters
const targetUrl = CONFIG.MODE === 'likers'
? `${window.location.href}/likes`
: `${window.location.href}/retweets`;
log(`Opening ${CONFIG.MODE} list...`, 'info');
window.location.href = targetUrl;
// Wait for page load
await sleep(3000);
log(`Starting to follow ${CONFIG.MODE} (max: ${CONFIG.MAX_FOLLOWS})`, 'info');
let scrolls = 0;
while (followCount < CONFIG.MAX_FOLLOWS && scrolls < 30) {
const cells = document.querySelectorAll(SELECTORS.userCell);
for (const cell of cells) {
if (followCount >= CONFIG.MAX_FOLLOWS) break;
// Skip protected if configured
if (CONFIG.SKIP_PROTECTED && cell.querySelector('[data-testid="icon-lock"]')) continue;
// Skip verified if configured
if (CONFIG.SKIP_VERIFIED && cell.querySelector('[data-testid="icon-verified"]')) continue;
if (await followUser(cell)) {
await sleep(CONFIG.DELAY_BETWEEN);
}
}
scrollBy(500);
scrolls++;
await sleep(2000);
}
log(`Done! Followed ${followCount} ${CONFIG.MODE}.`, 'success');
};
run();
})();
โ ๏ธ Follow Limits
- X has daily follow limits - don't exceed ~400/day
- Following too fast can trigger rate limits
- Keep
MAX_FOLLOWSreasonable per session - Use
DELAY_BETWEENof at least 2-3 seconds