X/Twitter Community Analytics: How to Discover & Analyze Twitter Communities
Twitter Communities are X's answer to Facebook Groups and Reddit subreddits — topic-focused spaces where people discuss specific interests. Since their expansion in 2025, Communities have become one of the most engaged features on X.
The engagement numbers are surprisingly good. Community posts often get 3-5x the replies of regular tweets because they're shown to a curated, interested audience rather than competing in the main feed.
But there's no built-in way to discover communities in your niche, compare their engagement, or analyze what content works within them. X's analytics don't cover Communities at all.
This guide shows you how to find relevant communities, analyze their activity and engagement, and monitor community conversations using API data.
What Community Data Can You Access?
Here's what you can pull from any public X Community:
Community Info
- Community name and ID
- Description and rules
- Member count
- Creation date
- Admin/moderator info
- Community banner and avatar
Community Tweets
- Full tweet text
- Like, reply, retweet, bookmark counts
- Author information
- Timestamps
- Quote tweets and threads
- View counts
That's everything you need to evaluate whether a community is worth joining, posting in, or monitoring.
Discover and Analyze Communities
Start by pulling data from a community you've found:
const axios = require('axios');
const API_KEY = process.env.SOCIAVAULT_API_KEY;
const BASE_URL = 'https://api.sociavault.com';
async function analyzeCommunity(communityUrl) {
// Get community info
const infoResponse = await axios.get(`${BASE_URL}/v1/scrape/twitter/community`, {
params: { url: communityUrl },
headers: { 'X-API-Key': API_KEY }
});
const community = infoResponse.data.data;
// Get community tweets
const tweetsResponse = await axios.get(`${BASE_URL}/v1/scrape/twitter/community/tweets`, {
params: { url: communityUrl },
headers: { 'X-API-Key': API_KEY }
});
const tweets = tweetsResponse.data.data || [];
console.log(`\n=== COMMUNITY ANALYSIS ===`);
console.log(`Name: ${community.name}`);
console.log(`Members: ${community.member_count?.toLocaleString()}`);
console.log(`Description: ${community.description?.substring(0, 200)}`);
console.log(`Created: ${community.created_at}`);
// Analyze tweet engagement
const tweetMetrics = tweets.map(t => {
const stats = t.statistics || t.legacy || {};
return {
text: (t.full_text || t.text || '').substring(0, 100),
author: t.author?.screen_name || t.user?.screen_name || 'unknown',
likes: stats.favorite_count || stats.like_count || 0,
replies: stats.reply_count || 0,
retweets: stats.retweet_count || 0,
views: stats.view_count || t.views?.count || 0,
engagement: (stats.favorite_count || stats.like_count || 0) +
(stats.reply_count || 0) +
(stats.retweet_count || 0)
};
});
const avgLikes = tweetMetrics.reduce((s, t) => s + t.likes, 0) / Math.max(tweetMetrics.length, 1);
const avgReplies = tweetMetrics.reduce((s, t) => s + t.replies, 0) / Math.max(tweetMetrics.length, 1);
const avgRetweets = tweetMetrics.reduce((s, t) => s + t.retweets, 0) / Math.max(tweetMetrics.length, 1);
console.log(`\nEngagement (${tweetMetrics.length} recent tweets):`);
console.log(` Avg likes: ${Math.round(avgLikes).toLocaleString()}`);
console.log(` Avg replies: ${Math.round(avgReplies).toLocaleString()}`);
console.log(` Avg retweets: ${Math.round(avgRetweets).toLocaleString()}`);
// Find top contributors
const authorCounts = {};
tweetMetrics.forEach(t => {
authorCounts[t.author] = (authorCounts[t.author] || 0) + 1;
});
const topContributors = Object.entries(authorCounts)
.sort((a, b) => b[1] - a[1])
.slice(0, 5);
console.log(`\nTop contributors:`);
topContributors.forEach(([author, count]) => {
console.log(` @${author}: ${count} posts`);
});
// Top post
tweetMetrics.sort((a, b) => b.engagement - a.engagement);
if (tweetMetrics.length > 0) {
const top = tweetMetrics[0];
console.log(`\nTop post by @${top.author}: "${top.text}..."`);
console.log(` ${top.likes} likes | ${top.replies} replies | ${top.retweets} RTs`);
}
return { community, tweets: tweetMetrics };
}
await analyzeCommunity('https://x.com/i/communities/1234567890');
Cost: 2 credits (1 community info + 1 tweets).
Compare Multiple Communities
Choosing which communities to invest time in? Compare engagement across several:
import requests
import os
API_KEY = os.getenv('SOCIAVAULT_API_KEY')
BASE_URL = 'https://api.sociavault.com'
headers = {'X-API-Key': API_KEY}
def compare_communities(community_urls):
"""Compare engagement metrics across multiple X Communities"""
results = []
for url in community_urls:
# Get community info
info_resp = requests.get(
f'{BASE_URL}/v1/scrape/twitter/community',
params={'url': url},
headers=headers
)
community = info_resp.json().get('data', {})
# Get tweets
tweets_resp = requests.get(
f'{BASE_URL}/v1/scrape/twitter/community/tweets',
params={'url': url},
headers=headers
)
tweets = tweets_resp.json().get('data', [])
total_engagement = 0
for tweet in tweets:
stats = tweet.get('statistics', tweet.get('legacy', {}))
total_engagement += (
stats.get('favorite_count', stats.get('like_count', 0)) +
stats.get('reply_count', 0) +
stats.get('retweet_count', 0)
)
avg_engagement = total_engagement / max(len(tweets), 1)
members = community.get('member_count', 0)
# Engagement per member ratio
eng_per_member = (avg_engagement / max(members, 1)) * 100
results.append({
'name': community.get('name', 'Unknown'),
'members': members,
'tweets_analyzed': len(tweets),
'avg_engagement': round(avg_engagement),
'eng_per_member': round(eng_per_member, 3),
'url': url
})
# Sort by engagement per member (activity quality)
results.sort(key=lambda r: r['eng_per_member'], reverse=True)
print('\n=== COMMUNITY COMPARISON ===\n')
print(f'{"Community":<30} {"Members":>10} {"Avg Eng":>10} {"Eng/Member":>12}')
print('-' * 65)
for r in results:
print(f"{r['name'][:30]:<30} {r['members']:>10,} {r['avg_engagement']:>10,} "
f"{r['eng_per_member']:>11.3f}%")
# Recommendation
best = results[0]
print(f'\nMost engaged community: {best["name"]} ({best["eng_per_member"]:.3f}% engagement per member)')
return results
compare_communities([
'https://x.com/i/communities/community-1',
'https://x.com/i/communities/community-2',
'https://x.com/i/communities/community-3'
])
What to look for:
- High engagement per member = active, engaged community (worth joining)
- High members, low engagement = ghost town (avoid)
- Low members, high engagement = niche but passionate (great for targeted reach)
Monitor Community Conversations
Track what a community is discussing over time — useful for content ideas, product feedback, and trend spotting:
async function monitorCommunityTopics(communityUrl) {
const response = await axios.get(`${BASE_URL}/v1/scrape/twitter/community/tweets`, {
params: { url: communityUrl },
headers: { 'X-API-Key': API_KEY }
});
const tweets = response.data.data || [];
// Extract topics and keywords
const words = {};
const hashtags = {};
const mentions = {};
tweets.forEach(tweet => {
const text = (tweet.full_text || tweet.text || '').toLowerCase();
// Count meaningful words
text.split(/\s+/).forEach(word => {
const clean = word.replace(/[^a-z0-9#@]/g, '');
if (clean.startsWith('#') && clean.length > 2) {
hashtags[clean] = (hashtags[clean] || 0) + 1;
} else if (clean.startsWith('@') && clean.length > 2) {
mentions[clean] = (mentions[clean] || 0) + 1;
} else if (clean.length > 4) {
const stopWords = new Set(['about', 'would', 'could', 'their', 'there',
'these', 'those', 'which', 'where', 'being', 'still', 'while',
'think', 'should', 'going', 'really', 'great', 'thing', 'things']);
if (!stopWords.has(clean)) {
words[clean] = (words[clean] || 0) + 1;
}
}
});
});
const topWords = Object.entries(words).sort((a, b) => b[1] - a[1]).slice(0, 15);
const topHashtags = Object.entries(hashtags).sort((a, b) => b[1] - a[1]).slice(0, 10);
const topMentions = Object.entries(mentions).sort((a, b) => b[1] - a[1]).slice(0, 10);
console.log(`\n=== COMMUNITY TOPIC ANALYSIS (${tweets.length} tweets) ===\n`);
console.log('Trending topics:');
topWords.forEach(([word, count]) => console.log(` "${word}" — ${count}x`));
if (topHashtags.length > 0) {
console.log('\nTop hashtags:');
topHashtags.forEach(([tag, count]) => console.log(` ${tag} — ${count}x`));
}
if (topMentions.length > 0) {
console.log('\nMost mentioned users:');
topMentions.forEach(([user, count]) => console.log(` ${user} — ${count}x`));
}
return { words: topWords, hashtags: topHashtags, mentions: topMentions };
}
await monitorCommunityTopics('https://x.com/i/communities/1234567890');
Using Communities for Content Research
Communities are goldmines for understanding what your audience cares about. The questions people ask, the complaints they share, and the links they post all feed into your content strategy.
def extract_content_ideas(community_url):
"""Turn community conversations into content ideas"""
tweets_resp = requests.get(
f'{BASE_URL}/v1/scrape/twitter/community/tweets',
params={'url': community_url},
headers=headers
)
tweets = tweets_resp.json().get('data', [])
questions = []
complaints = []
resource_shares = []
for tweet in tweets:
text = tweet.get('full_text', tweet.get('text', ''))
stats = tweet.get('statistics', tweet.get('legacy', {}))
engagement = (
stats.get('favorite_count', stats.get('like_count', 0)) +
stats.get('reply_count', 0)
)
if '?' in text and engagement > 5:
questions.append({'text': text[:150], 'engagement': engagement})
if any(w in text.lower() for w in ['frustrated', 'annoying', 'hate', 'why does', 'doesn\'t work', 'broken']):
complaints.append({'text': text[:150], 'engagement': engagement})
if 'http' in text and engagement > 10:
resource_shares.append({'text': text[:150], 'engagement': engagement})
print('\n=== CONTENT IDEAS FROM COMMUNITY ===\n')
print(f'Questions people ask ({len(questions)} found):')
for q in sorted(questions, key=lambda x: x['engagement'], reverse=True)[:5]:
print(f' [{q["engagement"]} eng] {q["text"]}')
print(f'\nCommon complaints ({len(complaints)} found):')
for c in sorted(complaints, key=lambda x: x['engagement'], reverse=True)[:5]:
print(f' [{c["engagement"]} eng] {c["text"]}')
print(f'\nPopular shared resources ({len(resource_shares)} found):')
for r in sorted(resource_shares, key=lambda x: x['engagement'], reverse=True)[:5]:
print(f' [{r["engagement"]} eng] {r["text"]}')
return {'questions': questions, 'complaints': complaints, 'resources': resource_shares}
extract_content_ideas('https://x.com/i/communities/1234567890')
Every question is a blog post idea. Every complaint is a product opportunity. Every popular resource tells you what formats your audience prefers.
Get Started
Sign up free — analyze any X Community's engagement and content.
Full Twitter/X API docs: docs.sociavault.com/api-reference/twitter
Related Reading
Found this helpful?
Share it with others who might benefit
Ready to Try SociaVault?
Start extracting social media data with our powerful API. No credit card required.