🚀 Growth Automation Suite on X (Twitter) — Follow + Like + Unfollow
All-in-one growth automation: keyword-based following, timeline engagement, and smart unfollowing — combined into a single session-based script. Free, no API key, no app install.
Works on: 🌐 Browser Console (requires core.js)
Difficulty: 🔴 Advanced
Time: ⏱️ Up to 30 minutes per session (configurable)
Requirements: A web browser logged into x.com
📖 For the quick-reference version, see growth-suite.md
🎯 Real-World Scenario
You want to grow your X account from 500 followers to 5,000. You've read all the growth hacking guides — they all say the same thing: follow relevant people in your niche, engage with their content, then unfollow the ones who don't follow back after a few days. But executing this strategy manually means running three separate scripts (keyword follow, auto-liker, smart unfollow) every day and keeping track of who you followed and when.
XActions' Growth Suite combines all three strategies into one automated session. You define your niche keywords (like "web3 developer," "DeFi builder"), target accounts, and limits. The script runs a 3-phase campaign: Phase 1 (keyword follow) searches for and follows relevant users, Phase 2 (timeline like) engages with your feed, Phase 3 (smart unfollow) cleans up non-followers past your grace period. One script, one paste, one session — then come back tomorrow and do it again.
Before XActions:
┌──────────────────────────────────────────────────────────────┐
│ Twitter Growth Loop (Manual / Multiple Scripts) │
├──────────────────────────────────────────────────────────────┤
│ │
│ Morning: │
│ 1. Run keyword follow script (5 min to set up) │
│ 2. Wait for it to finish │
│ 3. Run auto-liker script (3 min to set up) │
│ 4. Wait for it to finish │
│ 5. Run unfollow script (3 min to set up) │
│ 6. Wait for it to finish │
│ 7. Hope you didn't exceed any rate limits │
│ │
│ Scripts: 3 separate scripts to manage │
│ Setup time: ~15 min total │
│ Coordination: Manual (you're the scheduler) │
│ State tracking: Fragmented across scripts │
└──────────────────────────────────────────────────────────────┘
After XActions Growth Suite:
┌──────────────────────────────────────────────────────────────┐
│ Twitter Growth Loop (Growth Suite) │
├──────────────────────────────────────────────────────────────┤
│ │
│ Morning: │
│ 1. Paste core.js + growth suite. Press Enter. │
│ 2. Phase 1: Keyword follow (auto) │
│ 3. Phase 2: Timeline engagement (auto) │
│ 4. Phase 3: Smart unfollow (auto) │
│ 5. Done. Come back tomorrow. │
│ │
│ Scripts: 1 (Growth Suite handles everything) │
│ Setup time: ~2 min │
│ Coordination: Automatic (phases run sequentially) │
│ State tracking: Unified (all tracked in one place) │
└──────────────────────────────────────────────────────────────┘
📋 What This Does (Step by Step)
The Growth Suite runs 3 automated phases in sequence, with session duration and rate limits enforced across all actions:
Phase 1 — Keyword Follow
- 🔍 Searches each keyword — navigates to
x.com/search?q=KEYWORD&f=user - 📜 Scans user cells — extracts profiles from People results
- ➕ Follows matching users — with 3s+ delays
- 💾 Tracks followed users — persistent storage with follow timestamp
Phase 2 — Timeline Engagement
- 🏠 Returns to home timeline — navigates to
x.com/home - ❤️ Likes tweets — scrolls feed and likes tweets you haven't already liked
- 📜 Scrolls for more — loads additional content
Phase 3 — Smart Unfollow
- 📋 Finds expired follows — checks tracked users past the grace period
- 🔙 Unfollows non-followers — navigates to your following page and unfollows
- 📊 Reports results — prints combined session summary
┌──────────────────────────────────────────────────────────────┐
│ │
│ [Start Growth Suite Session] │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ PHASE 1 — Keyword Follow │ │
│ │ │ │
│ │ For each keyword: │ │
│ │ Navigate to search → People tab │ │
│ │ Scan cells → Filter → Follow │ │
│ │ Track: { username, timestamp, source } │ │
│ │ Respect: LIMITS.FOLLOWS per session │ │
│ └──────────────────────┬─────────────────────────────┘ │
│ │ │
│ ▼ │
│ [Session expired?] ──Yes──→ [Print summary] │
│ │ No │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ PHASE 2 — Timeline Engagement │ │
│ │ │ │
│ │ Navigate to home │ │
│ │ For each tweet: │ │
│ │ Already liked? → Skip │ │
│ │ Click Like → Track tweet ID │ │
│ │ Respect: LIMITS.LIKES per session │ │
│ └──────────────────────┬─────────────────────────────┘ │
│ │ │
│ ▼ │
│ [Session expired?] ──Yes──→ [Print summary] │
│ │ No │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ PHASE 3 — Smart Unfollow │ │
│ │ │ │
│ │ Find users followed > UNFOLLOW_AFTER_DAYS ago │ │
│ │ Navigate to your following page │ │
│ │ For each expired user found on page: │ │
│ │ Click Unfollow → Confirm │ │
│ │ Remove from tracked list │ │
│ │ Respect: LIMITS.UNFOLLOWS per session │ │
│ └──────────────────────┬─────────────────────────────┘ │
│ │ │
│ ▼ │
│ [Print combined session summary] │
│ │
└──────────────────────────────────────────────────────────────┘
🌐 Method 1: Browser Console (Copy-Paste)
Best for: Daily growth campaigns. Requires pasting core.js first.
Prerequisites
- Logged into your X/Twitter account in a web browser
- On a desktop/laptop (not mobile)
- On
x.com(any page — the script navigates automatically)
Step 1: Paste core.js first
Open DevTools Console (
F12→ Console). Paste the contents ofsrc/automation/core.jsand press Enter. You'll see✅ XActions Core loaded.
Step 2: Configure your strategy and paste
Edit KEYWORDS, TARGET_ACCOUNTS, and LIMITS below, then paste:
// ============================================
// XActions - Growth Automation Suite
// by nichxbt — https://xactions.app
// REQUIRES: Paste core.js first!
// All-in-one: keyword follow + auto-like + smart unfollow
// ============================================
(() => {
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;
// ============================================
// GROWTH STRATEGY — edit this!
// ============================================
const STRATEGY = {
// ── TARGETING ──
KEYWORDS: [
'web3 developer',
'solidity engineer',
'defi builder',
],
TARGET_ACCOUNTS: [
// 'vitalikbuterin',
// 'naval',
],
// ── ACTIONS ──
ACTIONS: {
FOLLOW: true,
LIKE: true,
UNFOLLOW: true,
},
// ── LIMITS (per session) ──
LIMITS: {
FOLLOWS: 20,
LIKES: 30,
UNFOLLOWS: 15,
},
// ── TIMING ──
TIMING: {
UNFOLLOW_AFTER_DAYS: 3,
DELAY_BETWEEN_ACTIONS: 3000,
SESSION_DURATION_MINUTES: 30,
},
// ── FILTERS ──
FILTERS: {
MIN_FOLLOWERS: 50,
MAX_FOLLOWERS: 50000,
MUST_HAVE_BIO: true,
SKIP_PRIVATE: true,
LANGUAGE: null,
},
};
// ============================================
// STATE
// ============================================
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 isSessionExpired = () => {
const elapsed = (Date.now() - state.startTime) / 1000 / 60;
return elapsed >= STRATEGY.TIMING.SESSION_DURATION_MINUTES;
};
const checkLimits = () => ({
canFollow: state.follows < STRATEGY.LIMITS.FOLLOWS,
canLike: state.likes < STRATEGY.LIMITS.LIKES,
canUnfollow: state.unfollows < STRATEGY.LIMITS.UNFOLLOWS,
});
// ── Follow ──
const doFollow = async (userCell) => {
if (!STRATEGY.ACTIONS.FOLLOW || !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;
};
// ── Like ──
const doLike = async (tweet) => {
if (!STRATEGY.ACTIONS.LIKE || !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;
};
// ── Smart Unfollow ──
const findExpiredFollows = () => {
const expired = [];
const threshold = STRATEGY.TIMING.UNFOLLOW_AFTER_DAYS * 24 * 60 * 60 * 1000;
for (const [username, data] of tracked.followed) {
if (Date.now() - data.at > threshold && !data.followedBack) expired.push(username);
}
return expired;
};
const doUnfollow = async (userCell, username) => {
if (!STRATEGY.ACTIONS.UNFOLLOW || !checkLimits().canUnfollow) return false;
const unfollowBtn = userCell.querySelector(SELECTORS.unfollowButton);
if (!unfollowBtn) return false;
await clickElement(unfollowBtn);
await sleep(500);
const confirmBtn = await waitForElement(SELECTORS.confirmButton, 2000);
if (confirmBtn) await clickElement(confirmBtn);
state.unfollows++;
tracked.followed.delete(username);
saveTracked();
log(`🔙 Unfollowed @${username} (${state.unfollows}/${STRATEGY.LIMITS.UNFOLLOWS})`, 'action');
return true;
};
// ── Phase 1: Keyword Follow ──
const phaseFollow = async () => {
if (!STRATEGY.ACTIONS.FOLLOW) return;
log('📍 Phase 1: Keyword Follow', 'info');
for (const keyword of STRATEGY.KEYWORDS) {
if (!state.isRunning || !checkLimits().canFollow || isSessionExpired()) break;
log(`Searching: "${keyword}"`, 'action');
window.location.href = `https://x.com/search?q=${encodeURIComponent(keyword)}&src=typed_query&f=user`;
await sleep(3000);
await waitForElement(SELECTORS.userCell, 10000);
let scrolls = 0;
while (scrolls < 10 && checkLimits().canFollow && state.isRunning) {
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);
scrolls++;
await sleep(2000);
}
}
};
// ── Phase 2: Timeline Engagement ──
const phaseLike = async () => {
if (!STRATEGY.ACTIONS.LIKE) return;
log('📍 Phase 2: Timeline Engagement', 'info');
window.location.href = 'https://x.com/home';
await sleep(3000);
let scrolls = 0;
while (scrolls < 20 && checkLimits().canLike && state.isRunning && !isSessionExpired()) {
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);
scrolls++;
await sleep(2000);
}
};
// ── Phase 3: Smart Unfollow ──
const phaseUnfollow = async () => {
if (!STRATEGY.ACTIONS.UNFOLLOW) return;
log('📍 Phase 3: Smart Unfollow', 'info');
const expired = findExpiredFollows();
if (expired.length === 0) { log('No expired follows to clean up', 'info'); return; }
log(`Found ${expired.length} users past ${STRATEGY.TIMING.UNFOLLOW_AFTER_DAYS}-day threshold`, 'info');
const username = document.querySelector('[data-testid="SideNav_AccountSwitcher_Button"]')
?.textContent?.match(/@(\w+)/)?.[1];
if (!username) return;
window.location.href = `https://x.com/${username}/following`;
await sleep(3000);
const expiredSet = new Set(expired);
let scrolls = 0;
while (scrolls < 50 && checkLimits().canUnfollow && state.isRunning && !isSessionExpired()) {
const cells = document.querySelectorAll(SELECTORS.userCell);
for (const cell of cells) {
if (!checkLimits().canUnfollow) break;
const link = cell.querySelector('a[href^="/"]');
const cellUser = link?.getAttribute('href')?.replace('/', '').toLowerCase();
if (cellUser && expiredSet.has(cellUser)) {
await doUnfollow(cell, cellUser);
await randomDelay(STRATEGY.TIMING.DELAY_BETWEEN_ACTIONS, STRATEGY.TIMING.DELAY_BETWEEN_ACTIONS * 1.5);
}
}
scrollBy(600);
scrolls++;
await sleep(2000);
}
};
// ── Main ──
const run = async () => {
console.log(`
╔═══════════════════════════════════════════════════════════╗
║ 🚀 XActions Growth Automation Suite ║
╠═══════════════════════════════════════════════════════════╣
║ Keywords: ${STRATEGY.KEYWORDS.slice(0, 3).join(', ').substring(0, 30).padEnd(30)} ║
║ Session: ${STRATEGY.TIMING.SESSION_DURATION_MINUTES} minutes ║
║ ║
║ Limits: ║
║ Follows: ${String(STRATEGY.LIMITS.FOLLOWS).padEnd(5)} | Likes: ${String(STRATEGY.LIMITS.LIKES).padEnd(5)} ║
║ Unfollows: ${String(STRATEGY.LIMITS.UNFOLLOWS).padEnd(5)} | After: ${STRATEGY.TIMING.UNFOLLOW_AFTER_DAYS} days ║
║ ║
║ Run stopGrowth() to stop early. ║
╚═══════════════════════════════════════════════════════════╝
`);
log(`Tracking ${tracked.followed.size} followed users`, 'info');
await phaseFollow();
if (state.isRunning && !isSessionExpired()) await phaseLike();
if (state.isRunning && !isSessionExpired()) await phaseUnfollow();
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 growth automation...', 'warning');
};
})();
Step 3: Watch the 3-phase campaign
╔═══════════════════════════════════════════════════════════╗
║ 🚀 XActions Growth Automation Suite ║
║ Keywords: web3 developer, solidity eng... ║
║ Session: 30 minutes ║
║ Limits: Follows: 20 | Likes: 30 ║
║ Unfollows: 15 | After: 3 days ║
╚═══════════════════════════════════════════════════════════╝
Tracking 47 followed users
📍 Phase 1: Keyword Follow
Searching: "web3 developer"
✅ Followed @soliditydev (1/20)
✅ Followed @web3alice (2/20)
✅ Followed @defiresearcher (3/20)
...
Searching: "solidity engineer"
...
📍 Phase 2: Timeline Engagement
❤️ Liked tweet (1/30)
❤️ Liked tweet (2/30)
...
📍 Phase 3: Smart Unfollow
Found 8 users past 3-day threshold
🔙 Unfollowed @inactiveuser (1/15)
🔙 Unfollowed @nofollowback (2/15)
...
╔═══════════════════════════════════════════════════════════╗
║ ✅ SESSION COMPLETE ║
║ Follows: 20 | Likes: 30 | Unfollows: 8 ║
║ Total tracked: 59 users ║
╚═══════════════════════════════════════════════════════════╝
⚙️ Configuration Reference
Strategy Settings
| Setting | Default | Description |
|---|---|---|
KEYWORDS |
['web3 developer', ...] |
Search terms for Phase 1 following |
TARGET_ACCOUNTS |
[] |
Accounts to engage with (reserved for future use) |
ACTIONS.FOLLOW |
true |
Enable/disable Phase 1 |
ACTIONS.LIKE |
true |
Enable/disable Phase 2 |
ACTIONS.UNFOLLOW |
true |
Enable/disable Phase 3 |
Limits (Per Session)
| Setting | Default | Description |
|---|---|---|
LIMITS.FOLLOWS |
20 |
Max follow actions |
LIMITS.LIKES |
30 |
Max like actions |
LIMITS.UNFOLLOWS |
15 |
Max unfollow actions |
Timing
| Setting | Default | Description |
|---|---|---|
UNFOLLOW_AFTER_DAYS |
3 |
Grace period before unfollowing |
DELAY_BETWEEN_ACTIONS |
3000 |
Milliseconds between each action |
SESSION_DURATION_MINUTES |
30 |
Hard session timeout |
Filters
| Setting | Default | Description |
|---|---|---|
MIN_FOLLOWERS |
50 |
Skip users with fewer followers |
MAX_FOLLOWERS |
50000 |
Skip mega-accounts |
MUST_HAVE_BIO |
true |
Skip users without a bio |
SKIP_PRIVATE |
true |
Skip private/protected accounts |
💡 Pro Tips
- Run the Growth Suite daily. The follow → like → unfollow loop compounds over time. After 2 weeks, you should see measurable follower growth if your content is good.
- Start conservative. Set FOLLOWS: 10, LIKES: 15, UNFOLLOWS: 5 for the first week. Increase gradually as you observe X's response.
- Set UNFOLLOW_AFTER_DAYS to 3–5. Too short (1 day) and you unfollow before they see your follow. Too long (14 days) and your following count inflates.
- Disable phases you don't need. Set
ACTIONS.UNFOLLOW: falseif you're just focused on growth. SetACTIONS.FOLLOW: falseif you only want engagement. - Check
storage.get('growth_followed')regularly. This shows all tracked users with timestamps and follow-back status. - Pair with Natural Flow. Run Growth Suite in the morning for strategic growth, then Natural Flow in the evening for organic engagement. Different scripts, complementary strategies.
⚠️ Important Warnings
Core.js required: Paste
core.jsbefore this script. If you see❌ Core module not loaded!, you forgot this step.
Rate limits are cumulative. All three phases share X's rate limits. Following 20 + liking 30 + unfollowing 15 = 65 actions in one session. Stay under 100 total actions per session.
Page navigation. The script navigates between search results, home timeline, and your following page. Don't interact with the page while it's running.
State persistence. Followed users are tracked in
sessionStorage(cleared on tab close). The unfollow grace period timer starts when you follow, so closing the tab resets your tracking. For persistent tracking across sessions, uselocalStorageby modifying thestoragecalls.
🔗 Related Features
- Natural Flow Tutorial — Human-like session with likes, replies, retweets, bookmarks
- Keyword Follow Tutorial — Standalone keyword follow (Phase 1 only)
- Auto-Liker Tutorial — Standalone auto-liker (Phase 2 only)
- Smart Unfollow Tutorial — Standalone unfollow with detailed logging (beyond Phase 3)
- Follow Target Followers Tutorial — Follow from competitor lists instead of keyword search
❓ FAQ
How is the Growth Suite different from running individual scripts?
The Growth Suite runs all three strategies (follow, like, unfollow) in a single session with unified state tracking, shared rate limits, and a session timeout. Individual scripts don't coordinate with each other — you'd have to manage timing and limits manually.
How does the smart unfollow know who to unfollow?
It checks the growth_followed storage for users who were followed more than UNFOLLOW_AFTER_DAYS days ago and haven't been marked as following back. It then navigates to your following page and unfollows matching accounts.
Can I run this multiple times per day?
Yes, but conservative limits are recommended. Running 2x per day with 20 follows + 30 likes per session is safer than 1x with 50 follows + 60 likes.
What happens when the session expires?
The script checks SESSION_DURATION_MINUTES between phases. If the timer expires during Phase 1, Phases 2 and 3 are skipped. The session summary still prints with whatever was accomplished.
Is this detectable by X?
The Growth Suite uses 3s+ delays between actions, stays within conservative limits, and mimics page navigation patterns. However, no automation is 100% safe. Start with lower limits and increase gradually.
Can I skip specific phases?
Yes. Set ACTIONS.FOLLOW: false, ACTIONS.LIKE: false, or ACTIONS.UNFOLLOW: false to disable individual phases.
Built with ❤️ by @nichxbt
xactions.app · GitHub
⚡ Ready to try Growth Automation Suite on X (Twitter) — Follow + Like + Unfollow?
XActions is 100% free and open-source. No API keys, no fees, no signup.
Browse All Scripts