Auto-Like Tweets: A Developer's Guide to Automated Engagement
June 18, 20266 min read
Liking tweets is the simplest form of engagement on Twitter. It costs nothing, takes a second, and puts your name in front of the tweet author. Automating this process — liking tweets that match specific keywords — is one of the most effective growth tactics for new accounts. Here's how to build it.
## How It Works
The flow is straightforward:
- Search for tweets matching your target keywords
- Filter out tweets you've already liked
- Like each remaining tweet via the API
- Log what you liked to avoid duplicates
- Repeat on a schedule
## Python Implementation
import requests
import time
import sqlite3
API_KEY = "YOUR_CHIRPAPI_KEY"
BASE_URL = "https://api.chirpapi.fun/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
# Keywords to target
KEYWORDS = ["python programming", "web development", "startup"]
db = sqlite3.connect("engagement.db")
db.execute("""CREATE TABLE IF NOT EXISTS liked_tweets (
tweet_id TEXT PRIMARY KEY,
liked_at TEXT DEFAULT CURRENT_TIMESTAMP
)""")
def is_already_liked(tweet_id):
row = db.execute(
"SELECT 1 FROM liked_tweets WHERE tweet_id=?", (tweet_id,)
).fetchone()
return row is not None
def search_and_like():
for keyword in KEYWORDS:
# Search for tweets
search_resp = requests.get(
f"{BASE_URL}/search",
headers=HEADERS,
params={"q": keyword, "count": 10},
timeout=10
)
if search_resp.status_code != 200:
print(f"Search failed for '{keyword}': {search_resp.status_code}")
continue
tweets = search_resp.json().get("tweets", [])
print(f"Found {len(tweets)} tweets for '{keyword}'")
for tweet in tweets:
tweet_id = tweet["id"]
if is_already_liked(tweet_id):
continue
# Like the tweet
like_resp = requests.post(
f"{BASE_URL}/like",
headers=HEADERS,
json={"tweet_id": tweet_id},
timeout=10
)
if like_resp.status_code == 200:
db.execute("INSERT OR IGNORE INTO liked_tweets (tweet_id) VALUES (?)", (tweet_id,))
db.commit()
print(f"Liked: {tweet.get('text', '')[:60]}...")
elif like_resp.status_code == 429:
print("Rate limited. Waiting 60 seconds...")
time.sleep(60)
else:
print(f"Like failed: {like_resp.status_code}")
# Random delay between likes (30-90 seconds)
time.sleep(random.randint(30, 90))
search_and_like()
## Node.js Implementation
const fetch = require('node-fetch');
const sqlite3 = require('better-sqlite3');
const API_KEY = 'YOUR_CHIRPAPI_KEY';
const BASE = 'https://api.chirpapi.fun/v1';
const db = sqlite3('engagement.db');
db.exec(`CREATE TABLE IF NOT EXISTS liked_tweets (
tweet_id TEXT PRIMARY KEY,
liked_at TEXT DEFAULT CURRENT_TIMESTAMP
)`);
const KEYWORDS = ['javascript', 'react', 'webdev'];
async function searchAndLike() {
for (const keyword of KEYWORDS) {
const searchRes = await fetch(
`${BASE}/search?q=${encodeURIComponent(keyword)}&count=10`,
{headers: {'Authorization': `Bearer ${API_KEY}`}}
);
if (!searchRes.ok) continue;
const {tweets} = await searchRes.json();
for (const tweet of tweets) {
const already = db.prepare(
'SELECT 1 FROM liked_tweets WHERE tweet_id=?'
).get(tweet.id);
if (already) continue;
const likeRes = await fetch(`${BASE}/like`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({tweet_id: tweet.id})
});
if (likeRes.ok) {
db.prepare('INSERT OR IGNORE INTO liked_tweets VALUES (?)').run(tweet.id);
console.log(`Liked: ${tweet.text.slice(0, 60)}...`);
}
// Wait 30-90 seconds between likes
await new Promise(r => setTimeout(r, 30000 + Math.random() * 60000));
}
}
}
searchAndLike();
## Rate Limit Handling
Twitter enforces rate limits. ChirpAPI forwards these limits. Key rules:
- **Likes:** ~300 per 15 minutes (official limit). Stay well under.
- **Search:** ~180 per 15 minutes.
- **Safe target:** 50-100 likes per hour for warm accounts, 20-30 for new accounts.
Always handle 429 responses with exponential backoff:
def like_with_backoff(tweet_id, max_retries=3):
for attempt in range(max_retries):
resp = requests.post(
f"{BASE_URL}/like",
headers=HEADERS,
json={"tweet_id": tweet_id},
timeout=10
)
if resp.status_code == 200:
return True
if resp.status_code == 429:
wait = 60 * (2 ** attempt) # 60s, 120s, 240s
print(f"Rate limited. Waiting {wait}s...")
time.sleep(wait)
else:
break
return False
## Safety: Account Warm-Up Schedule
New accounts should not start with heavy automation. Twitter watches for sudden spikes in activity.
- **Week 1:** 5-10 likes per day, spread across 8+ hours
- **Week 2:** 15-25 likes per day
- **Week 3:** 30-50 likes per day
- **Week 4+:** 50-100 likes per day (if no warnings)
If you receive a "your account looks automated" warning, stop all automation for 48 hours, then resume at half the previous rate.
## Keyword Selection Tips
- **Be specific:** "python async" is better than "programming"
- **Use quotes:** Search for exact phrases to reduce noise
- **Exclude retweets:** Add `-filter:retweets` to your search query
- **Target recent:** Add `since:2026-06-15` to avoid old tweets
- **Filter by engagement:** `min_faves:5` to skip tweets nobody cares about
Originally published at ChirpAPI Blog.
Top comments (0)