Tutorial
How to Monitor Replies to a Tweet (Automated)
Build an automated pipeline to track replies on any X/Twitter thread. Get notified via webhooks, Slack, or Discord when new replies appear.
Written by Alex P.
- twitter monitoring
- tweet replies
- X alerts
- twitter automation
- reply tracking
You launched a product, published an announcement, or someone is discussing your brand in a thread. You want to know who’s replying and what they’re saying — automatically.
Here’s how to build a reply monitor that checks any tweet on a schedule and alerts you when new replies come in.
The Architecture
Cron (every 2 min) → Fetch tweet replies → Filter new replies → Send alert
Step 1: Get Tweet Replies
The FetchLayer tweet-replies endpoint returns replies for any tweet by ID:
async function getReplies(tweetId) {
const res = await fetch('https://api.fetchlayer.dev/twitter/tweet-replies', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.FETCHLAYER_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ tweetId })
});
const data = await res.json();
return data.replies || [];
}
Why not use X’s official API? The official API charges $100/month minimum, rate-limits aggressively, and doesn’t provide reply threading on the Basic tier. FetchLayer gives you clean JSON with one API key and no OAuth ceremony.
Step 2: Track Seen Replies
import { readFileSync, writeFileSync, existsSync } from 'fs';
const SEEN_FILE = './seen-replies.json';
function loadSeen() {
if (!existsSync(SEEN_FILE)) return new Set();
return new Set(JSON.parse(readFileSync(SEEN_FILE, 'utf-8')));
}
function saveSeen(seen) {
writeFileSync(SEEN_FILE, JSON.stringify([...seen].slice(-2000)));
}
Step 3: Filter and Alert
// Only alert on replies from verified accounts or with high engagement
function isNotable(reply) {
return reply.author.isVerified || (reply.likeCount || 0) > 5;
}
async function sendAlert(reply, contextTweetId) {
const tweetUrl = `https://x.com/i/status/${contextTweetId}`;
await fetch(process.env.SLACK_WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text: `💬 New reply on tweet`,
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*@${reply.author.handle}* ${reply.author.isVerified ? '✓' : ''} replied:\n>${reply.text.slice(0, 280)}\n<${tweetUrl}|View thread> · ${reply.likeCount} likes`
}
}
]
})
});
}
Step 4: Full Script
// monitor-replies.mjs
const TWEET_ID = process.argv[2]; // Pass tweet ID as argument
async function run() {
if (!TWEET_ID) {
console.error('Usage: node monitor-replies.mjs <tweetId>');
process.exit(1);
}
const seen = loadSeen();
const replies = await getReplies(TWEET_ID);
const newReplies = replies.filter(r => !seen.has(r.id) && isNotable(r));
for (const reply of newReplies) {
await sendAlert(reply, TWEET_ID);
seen.add(reply.id);
console.log(` → Alerted: @${reply.author.handle}`);
}
saveSeen(seen);
console.log(`Checked: ${replies.length} replies, ${newReplies.length} new alerts`);
}
run().catch(console.error);
Step 5: Deploy
# Every 2 minutes, monitor replies to your launch tweet
*/2 * * * * cd /app && node monitor-replies.mjs "1942939879222220800" >> replies.log 2>&1
Advanced: Monitor Multiple Tweets
const WATCH_LIST = [
{ id: '1942939879222220800', label: 'Launch announcement' },
{ id: '1942939879222220801', label: 'Feature poll' },
];
async function runAll() {
const seen = loadSeen();
for (const { id, label } of WATCH_LIST) {
const replies = await getReplies(id);
const newReplies = replies.filter(r => !seen.has(r.id));
for (const reply of newReplies) {
await sendAlert(reply, id);
seen.add(reply.id);
console.log(`[${label}] Alerted: @${reply.author.handle}`);
}
}
saveSeen(seen);
}
What’s Next
- How to Monitor Twitter for Keywords — keyword monitoring
- How to Track Competitor Tweets — competitor tracking
- Twitter API with Node.js — full Node.js guide
- FetchLayer API Reference