🚀 Growth Suite
All-in-one growth automation combining follow + like + smart unfollow for X (Twitter).
⭐ Pro Feature
This is an advanced feature available in XActions Pro tier. Growth Suite combines multiple automation strategies into a single, intelligent workflow that grows your account organically while you focus on creating content.
📋 What It Does
The Growth Suite is your complete growth automation engine that:
- Keyword-Based Following - Searches for users by niche keywords and follows promising accounts
- Auto-Liking - Engages with content in your timeline to boost visibility
- Smart Unfollowing - Automatically unfollows users who don't follow back after a grace period
- Engagement Tracking - Remembers who you've followed/liked to avoid duplicates
- Session Management - Runs for configurable time periods with proper breaks
- Rate Limiting - Built-in delays and limits to protect your account
The Growth Flywheel:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 🔍 Search Keywords ──▶ 👤 Follow Users ──▶ ❤️ Like │
│ ▲ Content │
│ │ │ │
│ │ ▼ │
│ 📊 Track & ◀── 🔄 Smart Unfollow ◀── ⏰ Wait │
│ Analyze Non-Followers X Days │
│ │
└─────────────────────────────────────────────────────────────┘
Use cases:
- 📈 Grow a new account from zero to 10K followers
- 🎯 Build a niche-targeted audience (crypto, tech, marketing, etc.)
- 🤝 Increase engagement through strategic follows and likes
- 🧹 Maintain a healthy following/follower ratio
- ⏰ Save hours of daily manual engagement work
- 🔄 Run consistent growth campaigns on autopilot
⚠️ CRITICAL SAFETY WARNINGS
🚨 ACCOUNT SAFETY FIRST!
Aggressive automation WILL get your account restricted or permanently suspended.
X (Twitter) actively detects and penalizes bot-like behavior.
Before you start:
| ❌ DON'T | ✅ DO |
|---|---|
| Run 24/7 without breaks | Run 1-2 sessions per day max |
| Follow/unfollow hundreds per day | Stay under 30 follows per day |
| Use identical timing patterns | Randomize all delays |
| Run multiple scripts at once | Run one automation at a time |
| Start with high limits | Start LOW, increase gradually |
| Ignore warning signs | Stop immediately if rate limited |
Warning Signs to Watch For:
- 🔴 "You've reached your daily limit" messages
- 🔴 Temporary restrictions on following/liking
- 🔴 Account locked for suspicious activity
- 🔴 Captcha challenges appearing frequently
If you see these signs, STOP all automation for 24-48 hours!
⚙️ Configuration Options
Targeting
| Option | Type | Default | Description |
|---|---|---|---|
KEYWORDS |
string[] |
[] |
Keywords to search for (niche targeting) |
TARGET_ACCOUNTS |
string[] |
[] |
Accounts whose followers you want to target |
Actions
| Option | Type | Default | Description |
|---|---|---|---|
FOLLOW |
boolean |
true |
Enable following users from search |
LIKE |
boolean |
true |
Enable liking tweets in timeline |
UNFOLLOW |
boolean |
true |
Enable smart unfollowing |
Limits (Per Session)
| Option | Type | Default | Description |
|---|---|---|---|
FOLLOWS |
number |
20 |
Maximum follows per session |
LIKES |
number |
30 |
Maximum likes per session |
UNFOLLOWS |
number |
15 |
Maximum unfollows per session |
Timing
| Option | Type | Default | Description |
|---|---|---|---|
UNFOLLOW_AFTER_DAYS |
number |
3 |
Days to wait before unfollowing non-followers |
DELAY_BETWEEN_ACTIONS |
number |
3000 |
Milliseconds between actions |
SESSION_DURATION_MINUTES |
number |
30 |
How long each session runs |
Filters
| Option | Type | Default | Description |
|---|---|---|---|
MIN_FOLLOWERS |
number |
50 |
Skip accounts with fewer followers |
MAX_FOLLOWERS |
number |
50000 |
Skip accounts with more followers |
MUST_HAVE_BIO |
boolean |
true |
Only follow accounts with bios |
SKIP_PRIVATE |
boolean |
true |
Skip private/protected accounts |
LANGUAGE |
string | null |
null |
Filter by language ('en', 'es', etc.) |
🖥️ Example 1: Browser Console
Best for: Quick growth sessions, testing your strategy
Steps:
- Go to
x.com/home - Open browser console (F12 → Console tab)
- First paste
core.jsfrom the XActions repository - Then paste the growth script below
- Watch the magic happen!
// ============================================
// XActions - Growth Suite (Browser Console)
// Author: nich (@nichxbt)
// REQUIRES: Paste core.js first!
// ============================================
(() => {
if (!window.XActions?.Core) {
console.error('❌ Core module not loaded! Paste core.js first.');
return;
}
const { log, sleep, randomDelay, scrollBy, clickElement, waitForElement, storage, SELECTORS } = window.XActions.Core;
// ============================================
// 🎯 CONFIGURE YOUR GROWTH STRATEGY
// ============================================
const STRATEGY = {
// Keywords to search for (your niche)
KEYWORDS: [
'javascript developer',
'web developer',
'react developer',
],
// Enable/disable actions
ACTIONS: {
FOLLOW: true,
LIKE: true,
UNFOLLOW: true,
},
// ⚠️ KEEP THESE LOW for safety!
LIMITS: {
FOLLOWS: 15, // Per session
LIKES: 20, // Per session
UNFOLLOWS: 10, // Per session
},
// Timing settings
TIMING: {
UNFOLLOW_AFTER_DAYS: 3,
DELAY_BETWEEN_ACTIONS: 4000,
SESSION_DURATION_MINUTES: 25,
},
// User filters
FILTERS: {
MIN_FOLLOWERS: 50,
MAX_FOLLOWERS: 50000,
MUST_HAVE_BIO: true,
SKIP_PRIVATE: true,
},
};
// ============================================
// STATE & TRACKING
// ============================================
const state = { follows: 0, likes: 0, unfollows: 0, startTime: Date.now(), isRunning: true };
const tracked = {
followed: new Map(Object.entries(storage.get('growth_followed') || {})),
liked: new Set(storage.get('growth_liked') || []),
};
const saveTracked = () => {
storage.set('growth_followed', Object.fromEntries(tracked.followed));
storage.set('growth_liked', Array.from(tracked.liked));
};
const checkLimits = () => ({
canFollow: state.follows < STRATEGY.LIMITS.FOLLOWS,
canLike: state.likes < STRATEGY.LIMITS.LIKES,
canUnfollow: state.unfollows < STRATEGY.LIMITS.UNFOLLOWS,
});
const isSessionExpired = () => {
return (Date.now() - state.startTime) / 60000 >= STRATEGY.TIMING.SESSION_DURATION_MINUTES;
};
// ============================================
// ACTIONS
// ============================================
const doFollow = async (userCell) => {
if (!checkLimits().canFollow) return false;
const followBtn = userCell.querySelector(SELECTORS.followButton);
if (!followBtn) return false;
const link = userCell.querySelector('a[href^="/"]');
const username = link?.getAttribute('href')?.replace('/', '').toLowerCase();
if (!username || tracked.followed.has(username)) return false;
await clickElement(followBtn);
state.follows++;
tracked.followed.set(username, { at: Date.now(), source: 'growth' });
saveTracked();
log(`✅ Followed @${username} (${state.follows}/${STRATEGY.LIMITS.FOLLOWS})`, 'success');
return true;
};
const doLike = async (tweet) => {
if (!checkLimits().canLike) return false;
const likeBtn = tweet.querySelector(SELECTORS.likeButton);
if (!likeBtn) return false;
const tweetLink = tweet.querySelector('a[href*="/status/"]');
const tweetId = tweetLink?.href?.match(/status\/(\d+)/)?.[1];
if (!tweetId || tracked.liked.has(tweetId)) return false;
await clickElement(likeBtn);
state.likes++;
tracked.liked.add(tweetId);
saveTracked();
log(`❤️ Liked tweet (${state.likes}/${STRATEGY.LIMITS.LIKES})`, 'success');
return true;
};
// ============================================
// RUN
// ============================================
const run = async () => {
console.log(`
╔═══════════════════════════════════════════════════════════╗
║ 🚀 XActions Growth Suite - Pro ║
╠═══════════════════════════════════════════════════════════╣
║ Keywords: ${STRATEGY.KEYWORDS.slice(0, 2).join(', ').substring(0, 35).padEnd(35)} ║
║ Session: ${STRATEGY.TIMING.SESSION_DURATION_MINUTES} minutes ║
║ ║
║ Limits: ${STRATEGY.LIMITS.FOLLOWS} follows | ${STRATEGY.LIMITS.LIKES} likes | ${STRATEGY.LIMITS.UNFOLLOWS} unfollows ║
║ Grace period: ${STRATEGY.TIMING.UNFOLLOW_AFTER_DAYS} days ║
║ ║
║ Run: stopGrowth() to stop early ║
╚═══════════════════════════════════════════════════════════╝
`);
log(`📊 Tracking ${tracked.followed.size} previously followed users`, 'info');
// Phase 1: Follow
if (STRATEGY.ACTIONS.FOLLOW) {
log('📍 Phase 1: Keyword Search & Follow', 'info');
for (const keyword of STRATEGY.KEYWORDS) {
if (!state.isRunning || !checkLimits().canFollow) break;
log(`🔍 Searching: "${keyword}"`, 'action');
window.location.href = `https://x.com/search?q=${encodeURIComponent(keyword)}&f=user`;
await sleep(3000);
await waitForElement(SELECTORS.userCell, 10000);
for (let scroll = 0; scroll < 8 && checkLimits().canFollow; scroll++) {
const cells = document.querySelectorAll(SELECTORS.userCell);
for (const cell of cells) {
if (!checkLimits().canFollow) break;
if (cell.querySelector(SELECTORS.unfollowButton)) continue;
await doFollow(cell);
await randomDelay(STRATEGY.TIMING.DELAY_BETWEEN_ACTIONS, STRATEGY.TIMING.DELAY_BETWEEN_ACTIONS * 1.5);
}
scrollBy(600);
await sleep(2000);
}
}
}
// Phase 2: Like
if (STRATEGY.ACTIONS.LIKE && state.isRunning && !isSessionExpired()) {
log('📍 Phase 2: Timeline Engagement', 'info');
window.location.href = 'https://x.com/home';
await sleep(3000);
for (let scroll = 0; scroll < 15 && checkLimits().canLike; scroll++) {
const tweets = document.querySelectorAll(SELECTORS.tweet);
for (const tweet of tweets) {
if (!checkLimits().canLike) break;
if (tweet.querySelector(SELECTORS.unlikeButton)) continue;
await doLike(tweet);
await randomDelay(STRATEGY.TIMING.DELAY_BETWEEN_ACTIONS, STRATEGY.TIMING.DELAY_BETWEEN_ACTIONS * 1.5);
}
scrollBy(600);
await sleep(2000);
}
}
// Summary
console.log(`
╔═══════════════════════════════════════════════════════════╗
║ ✅ SESSION COMPLETE ║
╠═══════════════════════════════════════════════════════════╣
║ Follows: ${String(state.follows).padEnd(5)} ║
║ Likes: ${String(state.likes).padEnd(5)} ║
║ Unfollows: ${String(state.unfollows).padEnd(5)} ║
║ ║
║ Total tracked: ${String(tracked.followed.size).padEnd(5)} users ║
╚═══════════════════════════════════════════════════════════╝
`);
};
run();
window.stopGrowth = () => { state.isRunning = false; log('⏹️ Stopping...', 'warning'); };
})();
🖥️ Example 2: Node.js (Production-Ready)
Best for: Scheduled automation, long-term growth campaigns, server deployment
This production-ready script includes:
- ✅ Scheduled execution (runs automatically)
- ✅ Comprehensive logging with timestamps
- ✅ Persistent tracking across sessions
- ✅ Error handling and recovery
- ✅ Rate limit protection
- ✅ Progress reporting
// ============================================
// XActions Growth Suite - Node.js Production Script
// Author: nich (@nichxbt)
//
// Features:
// - Searches for users by keywords
// - Follows promising accounts
// - Likes their recent tweets
// - Unfollows non-followers after X days
// - Runs on schedule
// - Comprehensive logging
// ============================================
const { XActions } = require('xactions');
const fs = require('fs');
const path = require('path');
// ============================================
// 🎯 GROWTH STRATEGY CONFIGURATION
// ============================================
const STRATEGY = {
// Your niche keywords - be specific!
KEYWORDS: [
'web3 developer',
'solidity engineer',
'defi builder',
'ethereum dev',
'smart contract developer',
],
// Target accounts (follow their followers)
TARGET_ACCOUNTS: [
// Add usernames without @
],
// Daily limits - STAY CONSERVATIVE!
DAILY_LIMITS: {
FOLLOWS: 25,
LIKES: 40,
UNFOLLOWS: 20,
},
// Session settings
SESSION: {
DURATION_MINUTES: 30,
SESSIONS_PER_DAY: 2,
},
// Smart unfollow settings
UNFOLLOW: {
GRACE_PERIOD_DAYS: 3, // Wait this long before unfollowing
PROTECT_VERIFIED: true, // Don't unfollow verified accounts
PROTECT_ACTIVE: true, // Don't unfollow accounts that engage with you
},
// User filters
FILTERS: {
MIN_FOLLOWERS: 50,
MAX_FOLLOWERS: 50000,
MIN_FOLLOWING: 20,
MAX_FOLLOWING: 5000,
MUST_HAVE_BIO: true,
MUST_HAVE_AVATAR: true,
SKIP_PRIVATE: true,
ACCOUNT_AGE_DAYS: 30, // Skip accounts younger than this
LANGUAGE: 'en', // null for any language
},
// Timing (milliseconds)
DELAYS: {
BETWEEN_ACTIONS: { MIN: 3000, MAX: 6000 },
BETWEEN_USERS: { MIN: 2000, MAX: 4000 },
BATCH_PAUSE: { EVERY: 10, DURATION: 30000 },
SCROLL: 2000,
},
// Schedule (using cron syntax)
SCHEDULE: {
ENABLED: true,
// Run at 9 AM and 6 PM
CRON: '0 9,18 * * *',
},
};
// ============================================
// 📁 DATA STORAGE
// ============================================
const DATA_DIR = path.join(__dirname, '.growth-data');
const TRACKING_FILE = path.join(DATA_DIR, 'tracking.json');
const LOG_FILE = path.join(DATA_DIR, 'growth.log');
// Ensure data directory exists
if (!fs.existsSync(DATA_DIR)) {
fs.mkdirSync(DATA_DIR, { recursive: true });
}
// Load/save tracking data
const loadTracking = () => {
try {
if (fs.existsSync(TRACKING_FILE)) {
const data = JSON.parse(fs.readFileSync(TRACKING_FILE, 'utf8'));
return {
followed: new Map(Object.entries(data.followed || {})),
liked: new Set(data.liked || []),
unfollowed: new Set(data.unfollowed || []),
dailyStats: data.dailyStats || {},
};
}
} catch (err) {
console.error('Failed to load tracking data:', err);
}
return { followed: new Map(), liked: new Set(), unfollowed: new Set(), dailyStats: {} };
};
const saveTracking = (tracking) => {
const data = {
followed: Object.fromEntries(tracking.followed),
liked: Array.from(tracking.liked),
unfollowed: Array.from(tracking.unfollowed),
dailyStats: tracking.dailyStats,
};
fs.writeFileSync(TRACKING_FILE, JSON.stringify(data, null, 2));
};
// ============================================
// 📝 LOGGING
// ============================================
const log = (message, level = 'INFO') => {
const timestamp = new Date().toISOString();
const logLine = `[${timestamp}] [${level}] ${message}`;
console.log(logLine);
fs.appendFileSync(LOG_FILE, logLine + '\n');
};
// ============================================
// 🔧 HELPER FUNCTIONS
// ============================================
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const randomDelay = async (min, max) => {
const delay = min + Math.random() * (max - min);
await sleep(delay);
};
const getTodayKey = () => new Date().toISOString().split('T')[0];
const getDailyStats = (tracking) => {
const today = getTodayKey();
if (!tracking.dailyStats[today]) {
tracking.dailyStats[today] = { follows: 0, likes: 0, unfollows: 0 };
}
return tracking.dailyStats[today];
};
const canPerformAction = (tracking, action) => {
const stats = getDailyStats(tracking);
switch (action) {
case 'follow': return stats.follows < STRATEGY.DAILY_LIMITS.FOLLOWS;
case 'like': return stats.likes < STRATEGY.DAILY_LIMITS.LIKES;
case 'unfollow': return stats.unfollows < STRATEGY.DAILY_LIMITS.UNFOLLOWS;
default: return false;
}
};
const passesFilters = (user) => {
const f = STRATEGY.FILTERS;
if (user.followers < f.MIN_FOLLOWERS || user.followers > f.MAX_FOLLOWERS) return false;
if (user.following < f.MIN_FOLLOWING || user.following > f.MAX_FOLLOWING) return false;
if (f.MUST_HAVE_BIO && !user.bio) return false;
if (f.MUST_HAVE_AVATAR && user.hasDefaultAvatar) return false;
if (f.SKIP_PRIVATE && user.isProtected) return false;
if (f.LANGUAGE && user.language !== f.LANGUAGE) return false;
// Check account age
if (f.ACCOUNT_AGE_DAYS) {
const accountAge = (Date.now() - new Date(user.createdAt).getTime()) / (1000 * 60 * 60 * 24);
if (accountAge < f.ACCOUNT_AGE_DAYS) return false;
}
return true;
};
// ============================================
// 🚀 MAIN GROWTH CLASS
// ============================================
class GrowthSuite {
constructor(options = {}) {
this.auth = options.auth;
this.x = null;
this.tracking = loadTracking();
this.sessionStats = { follows: 0, likes: 0, unfollows: 0 };
this.isRunning = false;
}
async init() {
log('Initializing XActions Growth Suite...', 'INFO');
this.x = new XActions({
auth: this.auth,
rateLimit: {
enabled: true,
maxRetries: 3,
backoff: 'exponential',
},
});
await this.x.init();
log('XActions initialized successfully', 'INFO');
}
async searchAndFollow() {
log('📍 Phase 1: Keyword Search & Follow', 'INFO');
for (const keyword of STRATEGY.KEYWORDS) {
if (!this.isRunning || !canPerformAction(this.tracking, 'follow')) break;
log(`🔍 Searching for: "${keyword}"`, 'INFO');
try {
const users = await this.x.searchUsers(keyword, { limit: 50 });
log(`Found ${users.length} users for "${keyword}"`, 'INFO');
for (const user of users) {
if (!this.isRunning || !canPerformAction(this.tracking, 'follow')) break;
// Skip if already followed or doesn't pass filters
if (this.tracking.followed.has(user.username)) continue;
if (this.tracking.unfollowed.has(user.username)) continue;
if (!passesFilters(user)) continue;
try {
await this.x.follow(user.username);
this.tracking.followed.set(user.username, {
at: Date.now(),
source: 'keyword',
keyword: keyword,
followers: user.followers,
});
getDailyStats(this.tracking).follows++;
this.sessionStats.follows++;
saveTracking(this.tracking);
log(`✅ Followed @${user.username} (${user.followers} followers)`, 'SUCCESS');
// Batch pause
if (this.sessionStats.follows % STRATEGY.DELAYS.BATCH_PAUSE.EVERY === 0) {
log(`⏸️ Pausing for ${STRATEGY.DELAYS.BATCH_PAUSE.DURATION / 1000}s...`, 'INFO');
await sleep(STRATEGY.DELAYS.BATCH_PAUSE.DURATION);
}
await randomDelay(
STRATEGY.DELAYS.BETWEEN_ACTIONS.MIN,
STRATEGY.DELAYS.BETWEEN_ACTIONS.MAX
);
} catch (err) {
log(`Failed to follow @${user.username}: ${err.message}`, 'ERROR');
if (err.message.includes('rate limit')) {
log('Rate limited! Pausing for 5 minutes...', 'WARN');
await sleep(5 * 60 * 1000);
}
}
}
await randomDelay(
STRATEGY.DELAYS.BETWEEN_USERS.MIN,
STRATEGY.DELAYS.BETWEEN_USERS.MAX
);
} catch (err) {
log(`Search failed for "${keyword}": ${err.message}`, 'ERROR');
}
}
}
async likeTimeline() {
log('📍 Phase 2: Timeline Engagement', 'INFO');
if (!canPerformAction(this.tracking, 'like')) {
log('Daily like limit reached, skipping...', 'INFO');
return;
}
try {
const tweets = await this.x.getTimeline({ limit: 100 });
log(`Found ${tweets.length} tweets in timeline`, 'INFO');
for (const tweet of tweets) {
if (!this.isRunning || !canPerformAction(this.tracking, 'like')) break;
// Skip if already liked
if (this.tracking.liked.has(tweet.id)) continue;
if (tweet.isRetweet || tweet.isAd) continue;
try {
await this.x.likeTweet(tweet.id);
this.tracking.liked.add(tweet.id);
getDailyStats(this.tracking).likes++;
this.sessionStats.likes++;
saveTracking(this.tracking);
log(`❤️ Liked tweet from @${tweet.author.username}`, 'SUCCESS');
await randomDelay(
STRATEGY.DELAYS.BETWEEN_ACTIONS.MIN,
STRATEGY.DELAYS.BETWEEN_ACTIONS.MAX
);
} catch (err) {
log(`Failed to like tweet: ${err.message}`, 'ERROR');
}
}
} catch (err) {
log(`Timeline fetch failed: ${err.message}`, 'ERROR');
}
}
async smartUnfollow() {
log('📍 Phase 3: Smart Unfollow', 'INFO');
if (!canPerformAction(this.tracking, 'unfollow')) {
log('Daily unfollow limit reached, skipping...', 'INFO');
return;
}
const now = Date.now();
const gracePeriod = STRATEGY.UNFOLLOW.GRACE_PERIOD_DAYS * 24 * 60 * 60 * 1000;
const expired = [];
// Find users past grace period who haven't followed back
for (const [username, data] of this.tracking.followed) {
if (now - data.at > gracePeriod) {
expired.push({ username, data });
}
}
log(`Found ${expired.length} users past ${STRATEGY.UNFOLLOW.GRACE_PERIOD_DAYS}-day grace period`, 'INFO');
for (const { username, data } of expired) {
if (!this.isRunning || !canPerformAction(this.tracking, 'unfollow')) break;
try {
// Check if they follow us back
const followsBack = await this.x.checkFollowing(username);
if (followsBack) {
// They followed back! Update tracking
this.tracking.followed.set(username, { ...data, followedBack: true });
saveTracking(this.tracking);
log(`🤝 @${username} follows back - keeping!`, 'INFO');
continue;
}
// Check if verified and we should protect
if (STRATEGY.UNFOLLOW.PROTECT_VERIFIED) {
const user = await this.x.getUser(username);
if (user.isVerified) {
log(`✓ @${username} is verified - keeping!`, 'INFO');
continue;
}
}
// Unfollow
await this.x.unfollow(username);
this.tracking.followed.delete(username);
this.tracking.unfollowed.add(username);
getDailyStats(this.tracking).unfollows++;
this.sessionStats.unfollows++;
saveTracking(this.tracking);
log(`🔄 Unfollowed @${username} (no follow-back after ${STRATEGY.UNFOLLOW.GRACE_PERIOD_DAYS} days)`, 'SUCCESS');
await randomDelay(
STRATEGY.DELAYS.BETWEEN_ACTIONS.MIN,
STRATEGY.DELAYS.BETWEEN_ACTIONS.MAX
);
} catch (err) {
log(`Failed to process @${username}: ${err.message}`, 'ERROR');
}
}
}
async runSession() {
this.isRunning = true;
this.sessionStats = { follows: 0, likes: 0, unfollows: 0 };
const startTime = Date.now();
log('═'.repeat(60), 'INFO');
log('🚀 GROWTH SESSION STARTED', 'INFO');
log('═'.repeat(60), 'INFO');
log(`Keywords: ${STRATEGY.KEYWORDS.join(', ')}`, 'INFO');
log(`Daily limits: ${STRATEGY.DAILY_LIMITS.FOLLOWS} follows, ${STRATEGY.DAILY_LIMITS.LIKES} likes, ${STRATEGY.DAILY_LIMITS.UNFOLLOWS} unfollows`, 'INFO');
log(`Session duration: ${STRATEGY.SESSION.DURATION_MINUTES} minutes`, 'INFO');
log(`Tracked users: ${this.tracking.followed.size}`, 'INFO');
log('═'.repeat(60), 'INFO');
try {
// Phase 1: Search and Follow
await this.searchAndFollow();
// Check if session expired
const elapsed = (Date.now() - startTime) / 60000;
if (elapsed < STRATEGY.SESSION.DURATION_MINUTES && this.isRunning) {
// Phase 2: Like Timeline
await this.likeTimeline();
}
// Phase 3: Smart Unfollow
if (this.isRunning) {
await this.smartUnfollow();
}
} catch (err) {
log(`Session error: ${err.message}`, 'ERROR');
}
// Session summary
const duration = Math.round((Date.now() - startTime) / 60000);
log('═'.repeat(60), 'INFO');
log('✅ SESSION COMPLETE', 'INFO');
log('═'.repeat(60), 'INFO');
log(`Duration: ${duration} minutes`, 'INFO');
log(`Follows: ${this.sessionStats.follows}`, 'INFO');
log(`Likes: ${this.sessionStats.likes}`, 'INFO');
log(`Unfollows: ${this.sessionStats.unfollows}`, 'INFO');
log(`Total tracked: ${this.tracking.followed.size} users`, 'INFO');
log('═'.repeat(60), 'INFO');
this.isRunning = false;
}
stop() {
log('⏹️ Stopping growth session...', 'WARN');
this.isRunning = false;
}
}
// ============================================
// 🕐 SCHEDULER
// ============================================
const runScheduled = async () => {
const growth = new GrowthSuite({
auth: {
// Use environment variables!
username: process.env.X_USERNAME,
password: process.env.X_PASSWORD,
email: process.env.X_EMAIL,
},
});
await growth.init();
if (STRATEGY.SCHEDULE.ENABLED) {
const cron = require('node-cron');
log(`📅 Scheduler enabled: ${STRATEGY.SCHEDULE.CRON}`, 'INFO');
cron.schedule(STRATEGY.SCHEDULE.CRON, async () => {
log('⏰ Scheduled session triggered', 'INFO');
await growth.runSession();
});
// Run immediately on start
await growth.runSession();
} else {
// Run once
await growth.runSession();
process.exit(0);
}
};
// Handle graceful shutdown
process.on('SIGINT', () => {
log('Received SIGINT, shutting down...', 'WARN');
process.exit(0);
});
process.on('SIGTERM', () => {
log('Received SIGTERM, shutting down...', 'WARN');
process.exit(0);
});
// Start
runScheduled().catch((err) => {
log(`Fatal error: ${err.message}`, 'ERROR');
process.exit(1);
});
Running the Node.js Script
Install dependencies:
npm install xactions node-cron
Set environment variables:
export X_USERNAME="your_username"
export X_PASSWORD="your_password"
export X_EMAIL="your_email"
Run:
node growth-suite.js
Run with PM2 (production):
npm install -g pm2
pm2 start growth-suite.js --name "xactions-growth"
pm2 save
pm2 startup
📊 Safety Limits Reference
Recommended Daily Limits
| Account Age | Followers | Max Follows/Day | Max Unfollows/Day | Max Likes/Day |
|---|---|---|---|---|
| < 1 month | < 100 | 5-10 | 5 | 15-20 |
| 1-3 months | 100-500 | 10-15 | 10 | 25-30 |
| 3-6 months | 500-1K | 15-25 | 15 | 40-50 |
| 6-12 months | 1K-5K | 25-40 | 25 | 60-80 |
| > 1 year | 5K+ | 40-50 | 40 | 100 |
Session Limits
| Metric | Conservative | Moderate | Aggressive ⚠️ |
|---|---|---|---|
| Follows per session | 10-15 | 20-30 | 40-50 |
| Likes per session | 15-20 | 30-40 | 50-70 |
| Unfollows per session | 10-15 | 20-30 | 40-50 |
| Sessions per day | 1-2 | 2-3 | 3-4 |
| Session duration | 20-30 min | 30-45 min | 45-60 min |
| Delay between actions | 4-8 sec | 3-5 sec | 2-4 sec |
⚠️ Hard Limits (Never Exceed!)
| Action | Absolute Maximum | Why |
|---|---|---|
| Follows/day | 50 | X suspends aggressive followers |
| Unfollows/day | 50 | Pattern detection triggers |
| Likes/day | 100 | Rate limiting kicks in |
| Actions/hour | 30 | Velocity detection |
🎯 Growth Strategy Best Practices
1. Keyword Selection
DO:
- ✅ Use specific niche keywords (
"solidity engineer"not"developer") - ✅ Include job titles, technologies, interests
- ✅ Test different keywords and track results
- ✅ Focus on 3-5 high-quality keywords
DON'T:
- ❌ Use generic terms with millions of results
- ❌ Target unrelated niches for bigger numbers
- ❌ Change keywords too frequently
2. Timing Strategy
Optimal schedule:
Morning (9-10 AM): Session 1 - Focus on following
Evening (6-7 PM): Session 2 - Focus on engagement
Why this works:
- People are most active during these times
- Your follows/likes appear in their notifications when they're online
- Better chance of immediate engagement
3. The 3-Day Grace Period
The default 3-day unfollow window is strategic:
- Day 1-2: New follows see your profile, may check your content
- Day 3: Decision time - if they haven't followed back, they likely won't
- Day 4+: Unfollow to maintain ratio and free up capacity
4. Content Quality Matters
Automation amplifies your content, it doesn't replace it.
For best results:
- 📝 Post valuable content daily (2-3 tweets minimum)
- 🧵 Create threads on topics your target audience cares about
- 💬 Engage manually with replies that bring value
- 🎯 Have a clear bio and profile that explains who you are
5. The Follow-Back Flywheel
Better Content → More Follow-Backs → Better Ratio
↑ ↓
└──────── More Credibility ←─────────┘
🌐 Website Alternative
Prefer a no-code solution? The Growth Suite is available in the xactions.app Pro tier:
What's Included in Pro:
| Feature | Description |
|---|---|
| 🎯 Visual Strategy Builder | Configure growth campaigns with a simple UI |
| 📊 Analytics Dashboard | Track follower growth, engagement rates, best times |
| 📅 Smart Scheduler | AI-optimized timing for maximum engagement |
| 🔄 Auto-Unfollow | Automatic cleanup of non-followers |
| 📈 Progress Reports | Weekly email reports on your growth |
| 🛡️ Safety Monitoring | Automatic pausing when rate limits detected |
| 💾 Cloud Sync | Your data synced across devices |
| 🎧 Priority Support | Direct access to the team |
Getting Started with Pro:
- Visit xactions.app/pricing
- Sign up for Pro tier ($19/month)
- Connect your X account
- Configure your growth strategy
- Let it run on autopilot!
Pro Tip: Use the web app for daily automation and the scripts for more advanced customization.
🔧 Troubleshooting
"Rate limited" errors
Solution:
- Stop all automation immediately
- Wait 24-48 hours before resuming
- Reduce your limits by 50%
- Increase delays between actions
"Account locked" message
Solution:
- Complete any verification challenges
- Wait 48-72 hours before any automation
- Start with very conservative limits (5 follows/day)
- Mix in manual activity
Script stops unexpectedly
Possible causes:
- Session timeout - restart the script
- DOM changes - check for XActions updates
- Rate limiting - wait and retry
- Network issues - check your connection
Not finding users to follow
Solutions:
- Broaden your keywords
- Check if search is working manually
- Verify you're not shadow-banned
- Try different keyword combinations
📚 Related Documentation
- Auto-Liker - Standalone liking automation
- Keyword Follow - Focused following by keyword
- Unfollow Non-Followers - Cleanup non-followers
- Multi-Account - Run across multiple accounts
📜 License & Disclaimer
Author: nich (@nichxbt)
Disclaimer: This tool is for educational purposes. You are responsible for how you use it. Aggressive automation violates X's Terms of Service and can result in account suspension. Always use conservative limits and monitor your account's health.
License: MIT - See LICENSE for details.
⚡ Ready to try Growth Suite?
XActions is 100% free and open-source. No API keys, no fees, no signup.
Browse All Scripts