DEV Community

Cover image for Build a Twitter/X Community Tracker to Find Your Target Audience
Olamide Olaniyan
Olamide Olaniyan

Posted on

Build a Twitter/X Community Tracker to Find Your Target Audience

Twitter Communities are the most underrated feature on the platform.

500,000+ people in the "Indie Hackers" community. 200,000+ in "Tech Twitter." Thousands of niche communities with your exact target audienceβ€”all in one place.

But there's no good way to monitor them.

Until now.

In this tutorial, we'll build a Twitter Community Tracker that:

  1. Scrapes posts from any Twitter Community
  2. Identifies trending topics and influential members
  3. Helps you find the perfect time to engage

Why Communities Matter

Twitter's algorithm is brutal. Unless you have 50K+ followers, your tweets disappear into the void.

But Community posts? They get shown to every member of that community.

Post in the right community at the right time = guaranteed eyeballs from your target audience.

The Stack

  • Node.js: Runtime
  • SociaVault API: To scrape community data
  • OpenAI API: For trend analysis (optional)

Step 1: Setup

mkdir twitter-community-tracker
cd twitter-community-tracker
npm init -y
npm install axios dotenv openai node-cron
Enter fullscreen mode Exit fullscreen mode

Create .env:

SOCIAVAULT_API_KEY=your_sociavault_key
OPENAI_API_KEY=your_openai_key
Enter fullscreen mode Exit fullscreen mode

Step 2: Fetch Community Info

First, let's get the basic info about a community.

Create index.js:

require('dotenv').config();
const axios = require('axios');
const OpenAI = require('openai');

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const SOCIAVAULT_BASE = 'https://api.sociavault.com';

async function getCommunityInfo(communityUrl) {
  console.log('πŸ“₯ Fetching community info...');

  try {
    const response = await axios.get(`${SOCIAVAULT_BASE}/v1/scrape/twitter/community`, {
      params: { url: communityUrl },
      headers: { 'Authorization': `Bearer ${process.env.SOCIAVAULT_API_KEY}` }
    });

    return response.data.data;
  } catch (error) {
    console.error('Error fetching community:', error.message);
    return null;
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Get Community Posts

Now the good stuffβ€”let's fetch recent posts from the community:

async function getCommunityTweets(communityUrl) {
  console.log('πŸ“₯ Fetching community tweets...');

  try {
    const response = await axios.get(`${SOCIAVAULT_BASE}/v1/scrape/twitter/community/tweets`, {
      params: { url: communityUrl },
      headers: { 'Authorization': `Bearer ${process.env.SOCIAVAULT_API_KEY}` }
    });

    const tweets = response.data.data || [];

    return tweets.map(t => ({
      id: t.id || t.rest_id,
      author: t.user?.screen_name || t.author_handle,
      authorName: t.user?.name || t.author_name,
      text: t.full_text || t.text,
      likes: t.favorite_count || t.likes || 0,
      retweets: t.retweet_count || t.retweets || 0,
      replies: t.reply_count || t.replies || 0,
      date: t.created_at
    }));
  } catch (error) {
    console.error('Error fetching community tweets:', error.message);
    return [];
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Analyze Community Patterns

Let's build functions to understand the community dynamics:

function analyzeEngagement(tweets) {
  if (tweets.length === 0) return null;

  // Sort by engagement
  const byEngagement = [...tweets].sort((a, b) => 
    (b.likes + b.retweets + b.replies) - (a.likes + a.retweets + a.replies)
  );

  // Calculate averages
  const totalEngagement = tweets.reduce((sum, t) => 
    sum + t.likes + t.retweets + t.replies, 0
  );
  const avgEngagement = totalEngagement / tweets.length;

  // Find top posters
  const posterCounts = {};
  tweets.forEach(t => {
    posterCounts[t.author] = (posterCounts[t.author] || 0) + 1;
  });

  const topPosters = Object.entries(posterCounts)
    .sort((a, b) => b[1] - a[1])
    .slice(0, 10)
    .map(([author, count]) => ({ author, posts: count }));

  // Find top engaged posts
  const topPosts = byEngagement.slice(0, 5).map(t => ({
    author: t.author,
    text: t.text.substring(0, 100) + '...',
    engagement: t.likes + t.retweets + t.replies
  }));

  return {
    totalPosts: tweets.length,
    avgEngagement: avgEngagement.toFixed(1),
    topPosters,
    topPosts
  };
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Identify Content Themes

Use AI to understand what performs well in the community:

async function analyzeContentThemes(tweets) {
  console.log('πŸ€– Analyzing content themes...');

  // Get top performing tweets for analysis
  const topTweets = [...tweets]
    .sort((a, b) => (b.likes + b.retweets) - (a.likes + a.retweets))
    .slice(0, 30);

  const prompt = `
    Analyze these top-performing tweets from a Twitter Community.

    Return JSON with:
    {
      "themes": [top 5 content themes that get engagement],
      "formats": [top 3 post formats that work (threads, questions, hot takes, etc.)],
      "bestPractices": [5 specific tips for posting in this community],
      "contentIdeas": [5 specific post ideas that would likely perform well],
      "avoid": [3 things to avoid based on what doesn't get engagement]
    }

    Tweets:
    ${JSON.stringify(topTweets.map(t => ({ text: t.text, engagement: t.likes + t.retweets })))}
  `;

  const completion = await openai.chat.completions.create({
    model: 'gpt-4o-mini',
    messages: [{ role: 'user', content: prompt }],
    response_format: { type: 'json_object' }
  });

  return JSON.parse(completion.choices[0].message.content);
}
Enter fullscreen mode Exit fullscreen mode

Step 6: Find Your People

Identify community members who engage with content like yours:

async function findRelevantMembers(tweets, yourKeywords) {
  console.log('πŸ” Finding relevant community members...');

  const relevantTweets = tweets.filter(t => {
    const text = t.text.toLowerCase();
    return yourKeywords.some(kw => text.includes(kw.toLowerCase()));
  });

  // Extract unique authors who post about your topics
  const relevantAuthors = {};
  relevantTweets.forEach(t => {
    if (!relevantAuthors[t.author]) {
      relevantAuthors[t.author] = {
        author: t.author,
        authorName: t.authorName,
        relevantPosts: 0,
        totalEngagement: 0
      };
    }
    relevantAuthors[t.author].relevantPosts++;
    relevantAuthors[t.author].totalEngagement += t.likes + t.retweets;
  });

  return Object.values(relevantAuthors)
    .sort((a, b) => b.totalEngagement - a.totalEngagement)
    .slice(0, 20);
}
Enter fullscreen mode Exit fullscreen mode

Step 7: The Full Analysis

async function trackCommunity(communityUrl, keywords = []) {
  console.log('\n🐦 Twitter Community Tracker\n');
  console.log('═══════════════════════════════════════\n');

  // 1. Get community info
  const community = await getCommunityInfo(communityUrl);
  if (community) {
    console.log(`πŸ“ ${community.name}`);
    console.log(`πŸ‘₯ ${Number(community.member_count || 0).toLocaleString()} members`);
    console.log(`πŸ“ ${community.description?.substring(0, 100) || 'No description'}...\n`);
  }

  // 2. Get recent tweets
  const tweets = await getCommunityTweets(communityUrl);
  if (tweets.length === 0) {
    console.log('No tweets found.');
    return;
  }

  console.log(`βœ… Fetched ${tweets.length} recent posts\n`);

  // 3. Analyze engagement patterns
  const engagement = analyzeEngagement(tweets);

  console.log('═══════════════════════════════════════');
  console.log('πŸ“Š ENGAGEMENT ANALYSIS');
  console.log('═══════════════════════════════════════\n');

  console.log(`πŸ“ˆ Avg engagement per post: ${engagement.avgEngagement}`);

  console.log('\nπŸ‘‘ Most Active Posters:');
  engagement.topPosters.slice(0, 5).forEach((p, i) => {
    console.log(`  ${i + 1}. @${p.author} (${p.posts} posts)`);
  });

  console.log('\nπŸ”₯ Top Performing Posts:');
  engagement.topPosts.forEach((p, i) => {
    console.log(`  ${i + 1}. @${p.author} - ${p.engagement} engagements`);
    console.log(`     "${p.text}"`);
  });

  // 4. AI Content Analysis
  const themes = await analyzeContentThemes(tweets);

  console.log('\n═══════════════════════════════════════');
  console.log('🎯 CONTENT STRATEGY');
  console.log('═══════════════════════════════════════\n');

  console.log('πŸ“Œ Top Themes:');
  themes.themes.forEach((t, i) => console.log(`  ${i + 1}. ${t}`));

  console.log('\n✨ Winning Formats:');
  themes.formats.forEach((f, i) => console.log(`  ${i + 1}. ${f}`));

  console.log('\nπŸ’‘ Content Ideas for You:');
  themes.contentIdeas.forEach((idea, i) => console.log(`  ${i + 1}. ${idea}`));

  console.log('\n⚠️ What to Avoid:');
  themes.avoid.forEach((a, i) => console.log(`  ${i + 1}. ${a}`));

  // 5. Find relevant members (if keywords provided)
  if (keywords.length > 0) {
    const members = await findRelevantMembers(tweets, keywords);

    console.log('\n═══════════════════════════════════════');
    console.log(`🎯 MEMBERS TALKING ABOUT: ${keywords.join(', ')}`);
    console.log('═══════════════════════════════════════\n');

    members.forEach((m, i) => {
      console.log(`  ${i + 1}. @${m.author}`);
      console.log(`     ${m.relevantPosts} relevant posts, ${m.totalEngagement} total engagement`);
    });
  }

  return { community, tweets, engagement, themes };
}
Enter fullscreen mode Exit fullscreen mode

Step 8: Run It

async function main() {
  // Replace with your target community
  const communityUrl = 'https://twitter.com/i/communities/1234567890';

  // Keywords related to your product/niche
  const myKeywords = ['API', 'scraping', 'data', 'automation'];

  await trackCommunity(communityUrl, myKeywords);
}

main();
Enter fullscreen mode Exit fullscreen mode

Sample Output

🐦 Twitter Community Tracker
═══════════════════════════════════════

πŸ“ Indie Hackers
πŸ‘₯ 523,847 members
πŸ“ A community for indie hackers building profitable online businesses...

βœ… Fetched 48 recent posts

═══════════════════════════════════════
πŸ“Š ENGAGEMENT ANALYSIS
═══════════════════════════════════════

πŸ“ˆ Avg engagement per post: 47.3

πŸ‘‘ Most Active Posters:
  1. @levelsio (12 posts)
  2. @marc_louvion (8 posts)
  3. @tdinh_me (6 posts)
  4. @dannypostmaa (5 posts)
  5. @arlogilbert (4 posts)

πŸ”₯ Top Performing Posts:
  1. @levelsio - 847 engagements
     "Just crossed $100K MRR with a single product. No employees. No fund..."
  2. @marc_louvion - 523 engagements
     "The best marketing strategy in 2024: Build in public. Here's why..."

═══════════════════════════════════════
🎯 CONTENT STRATEGY
═══════════════════════════════════════

πŸ“Œ Top Themes:
  1. Revenue milestones and financial transparency
  2. Product launch announcements
  3. Build-in-public updates
  4. Lessons learned from failures
  5. Tech stack discussions

✨ Winning Formats:
  1. Personal stories with specific numbers
  2. Thread breakdowns of strategies
  3. Hot takes that challenge conventional wisdom

πŸ’‘ Content Ideas for You:
  1. "I built X in Y days - here's my exact tech stack"
  2. "The real cost breakdown of running my SaaS"
  3. "Why I stopped doing [popular thing] and what I do instead"
  4. "Unpopular opinion: [controversial take about building products]"
  5. "My first $X from [product] - lessons learned"

⚠️ What to Avoid:
  1. Promotional posts without value
  2. Generic advice without personal experience
  3. Asking for help without showing what you've tried
Enter fullscreen mode Exit fullscreen mode

Multi-Community Monitoring

Track multiple communities at once:

const cron = require('node-cron');

const COMMUNITIES = [
  { url: 'https://twitter.com/i/communities/123', name: 'Indie Hackers' },
  { url: 'https://twitter.com/i/communities/456', name: 'Tech Twitter' },
  { url: 'https://twitter.com/i/communities/789', name: 'SaaS Builders' }
];

// Check hourly for new opportunities
cron.schedule('0 * * * *', async () => {
  for (const community of COMMUNITIES) {
    console.log(`\nChecking ${community.name}...`);

    const tweets = await getCommunityTweets(community.url);

    // Find posts you should reply to
    const relevantPosts = tweets.filter(t => {
      const text = t.text.toLowerCase();
      return (
        text.includes('api') ||
        text.includes('scraping') ||
        text.includes('recommend')
      );
    });

    if (relevantPosts.length > 0) {
      console.log(`Found ${relevantPosts.length} relevant posts to engage with!`);
      // Send notification, add to queue, etc.
    }
  }
});
Enter fullscreen mode Exit fullscreen mode

Why This Matters

Twitter Communities are:

  • Curated audiences (everyone opted-in to the topic)
  • Higher engagement (posts shown to all members)
  • Less noise (no algorithm dilution)

Most people don't even know they exist. The ones who do are too lazy to monitor them properly.

Now you have an unfair advantage.

Get Started

  1. Get your SociaVault API Key
  2. Find communities in your niche
  3. Start tracking what works
  4. Post when you have something valuable to add

Stop shouting into the void. Start engaging where your audience already is.

Top comments (0)