Documentation Index
Fetch the complete documentation index at: https://docs.sorsa.io/llms.txt
Use this file to discover all available pages before exploring further.
How to Extract Members, Tweets, and Followers from X Lists and Communities via API
X Lists and X Communities are two ways to organize groups of accounts on the platform. Lists are curated feeds - you (or anyone) can create a list, add up to 5,000 members, and use it as a filtered timeline. Communities are opt-in groups centered around a topic, where members post and discuss within the community space.
Both are valuable data sources. A well-maintained industry list is a hand-curated roster of relevant accounts. A community is a self-selected group of people who care about a specific topic. Sorsa API provides endpoints to extract members, tweets, and followers from both, giving you structured access to these pre-filtered audiences and content feeds.
Lists: Overview
An X List is a curated collection of accounts. Any user can create a list, add members, and either keep it private or make it public. Public lists are accessible via the API. Lists have two audiences: members (the accounts added to the list) and followers (users who subscribe to the list’s feed).
Sorsa provides three List endpoints:
| Endpoint | Method | What it returns |
|---|
GET /v3/list-members | GET | User profiles of accounts in the list |
GET /v3/list-followers | GET | User profiles of accounts following the list |
GET /v3/list-tweets | GET | Recent tweets from all list members |
Getting List Members
Endpoint: GET /v3/list-members
Returns the profiles of all accounts included in a list. You need the List ID, which you can find in the list’s URL (e.g., https://x.com/i/lists/1234567890 -> ID is 1234567890).
curl "https://api.sorsa.io/v3/list-members?list_id=1234567890" \
-H "ApiKey: YOUR_API_KEY"
import requests
API_KEY = "YOUR_API_KEY"
def get_list_members(list_id):
resp = requests.get(
"https://api.sorsa.io/v3/list-members",
headers={"ApiKey": API_KEY},
params={"list_id": list_id},
)
resp.raise_for_status()
return resp.json().get("users", [])
members = get_list_members("1234567890")
for u in members[:10]:
print(f"@{u['username']} ({u['followers_count']:,} followers): {u.get('description', '')[:60]}")
| Parameter | Type | Required | Description |
|---|
list_id | string | Yes | The numeric List ID. |
The response is a UsersResponse with full user profile objects.
Getting List Followers
Endpoint: GET /v3/list-followers
Returns users who subscribe to (follow) the list. These are people who actively chose to see this curated feed - a strong signal of interest in the list’s topic.
import time
def get_list_followers(list_link, max_pages=10):
"""Fetch users who follow a specific X List."""
all_users = []
next_cursor = None
for page in range(max_pages):
params = {"list_link": list_link}
if next_cursor:
params["next_cursor"] = next_cursor
resp = requests.get(
"https://api.sorsa.io/v3/list-followers",
headers={"ApiKey": API_KEY},
params=params,
)
resp.raise_for_status()
data = resp.json()
users = data.get("users", [])
all_users.extend(users)
next_cursor = data.get("next_cursor")
if not next_cursor:
break
time.sleep(0.1)
return all_users
followers = get_list_followers("https://x.com/i/lists/1234567890")
print(f"{len(followers)} users follow this list")
| Parameter | Type | Required | Description |
|---|
list_link | string | Yes | The list URL or ID. |
next_cursor | string | No | Pagination cursor. |
Endpoint: GET /v3/list-tweets
Returns recent tweets from all members of the list, combined into a single chronological feed. This is the endpoint used in the Real-Time Monitoring guide for tracking groups of accounts with a single request.
def get_list_tweets(list_id, max_pages=5):
"""Fetch recent tweets from all members of a list."""
all_tweets = []
cursor = None
for page in range(max_pages):
params = {"list_id": list_id}
if cursor:
params["cursor"] = cursor
resp = requests.get(
"https://api.sorsa.io/v3/list-tweets",
headers={"ApiKey": API_KEY},
params=params,
)
resp.raise_for_status()
data = resp.json()
tweets = data.get("tweets", [])
all_tweets.extend(tweets)
cursor = data.get("next_cursor")
if not cursor:
break
time.sleep(0.1)
return all_tweets
tweets = get_list_tweets("1234567890", max_pages=10)
print(f"Collected {len(tweets)} tweets from list members")
for t in tweets[:5]:
print(f"@{t['user']['username']}: {t['full_text'][:80]}...")
| Parameter | Type | Required | Description |
|---|
list_id | string | Yes | The numeric List ID. |
cursor | string | No | Pagination cursor. |
Communities: Overview
X Communities are topic-based groups where users can join, post, and interact. Unlike lists (where a curator adds members), community members opt in themselves. This makes community member lists a reliable signal of genuine interest in a topic.
Sorsa provides three Community endpoints:
| Endpoint | Method | What it returns |
|---|
POST /v3/community-members | POST | User profiles of community members |
POST /v3/community-tweets | POST | Tweets posted within the community |
POST /v3/community-search-tweets | POST | Tweets within the community matching a search query |
You need the Community ID, found in the community URL: https://x.com/i/communities/1966045657589813686 -> ID is 1966045657589813686.
Endpoint: POST /v3/community-members
Returns the profiles of users who have joined the community.
curl -X POST https://api.sorsa.io/v3/community-members \
-H "ApiKey: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"community_link": "1966045657589813686"}'
def get_community_members(community_id, max_pages=10):
"""Extract members of an X Community."""
all_members = []
next_cursor = None
for page in range(max_pages):
body = {"community_link": community_id}
if next_cursor:
body["next_cursor"] = next_cursor
resp = requests.post(
"https://api.sorsa.io/v3/community-members",
headers={"ApiKey": API_KEY, "Content-Type": "application/json"},
json=body,
)
resp.raise_for_status()
data = resp.json()
users = data.get("users", [])
all_members.extend(users)
next_cursor = data.get("next_cursor")
if not next_cursor:
break
time.sleep(0.1)
return all_members
members = get_community_members("1966045657589813686")
print(f"Community has {len(members)} extractable members")
| Parameter | Type | Required | Description |
|---|
community_link | string | Yes | Community ID or full URL. |
next_cursor | string | No | Pagination cursor. |
Endpoint: POST /v3/community-tweets
Returns tweets posted within the community feed. You can sort by "latest" (chronological) or "popular" (engagement-ranked).
def get_community_tweets(community_id, order="latest", max_pages=5):
"""Fetch tweets from a community feed."""
all_tweets = []
next_cursor = None
for page in range(max_pages):
body = {"community_id": community_id, "order_by": order}
if next_cursor:
body["next_cursor"] = next_cursor
resp = requests.post(
"https://api.sorsa.io/v3/community-tweets",
headers={"ApiKey": API_KEY, "Content-Type": "application/json"},
json=body,
)
resp.raise_for_status()
data = resp.json()
tweets = data.get("tweets", [])
all_tweets.extend(tweets)
next_cursor = data.get("next_cursor")
if not next_cursor:
break
time.sleep(0.1)
return all_tweets
tweets = get_community_tweets("1966045657589813686", order="popular")
print(f"Collected {len(tweets)} community tweets")
for t in tweets[:5]:
print(f"@{t['user']['username']} ({t.get('likes_count', 0)} likes): {t['full_text'][:80]}...")
| Parameter | Type | Required | Description |
|---|
community_id | string | Yes | The numeric Community ID. |
order_by | string | No | "latest" (default) or "popular". |
next_cursor | string | No | Pagination cursor. |
Endpoint: POST /v3/community-search-tweets
Search for specific keywords within a community’s posts. Useful for finding discussions about a particular subtopic, product, or event within the broader community.
def search_community_tweets(community_link, query, order="popular", max_pages=5):
"""Search for tweets within a community by keyword."""
all_tweets = []
next_cursor = None
for page in range(max_pages):
body = {
"community_link": community_link,
"query": query,
"order_by": order,
}
if next_cursor:
body["next_cursor"] = next_cursor
resp = requests.post(
"https://api.sorsa.io/v3/community-search-tweets",
headers={"ApiKey": API_KEY, "Content-Type": "application/json"},
json=body,
)
resp.raise_for_status()
data = resp.json()
tweets = data.get("tweets", [])
all_tweets.extend(tweets)
next_cursor = data.get("next_cursor")
if not next_cursor:
break
time.sleep(0.1)
return all_tweets
# Find discussions about "API" in an Indie Hackers community
results = search_community_tweets(
"https://x.com/i/communities/1966045657589813686",
query="API",
order="popular",
)
print(f"Found {len(results)} community posts about 'API'")
| Parameter | Type | Required | Description |
|---|
community_link | string | Yes | Community URL or ID. |
query | string | Yes | Search keyword. |
order_by | string | No | "popular" or "latest". |
next_cursor | string | No | Pagination cursor. |
Practical Applications
Using Lists for Efficient Monitoring
The primary power of lists in the Sorsa ecosystem is efficiency. Instead of polling 50 individual accounts, you create one list with all 50 and poll /list-tweets once. This is covered in detail in the Real-Time Monitoring guide, but here is the setup checklist:
- Go to X Lists and create a new public list (private lists cannot be accessed via API).
- Add the accounts you want to track (up to 5,000).
- Copy the List ID from the URL.
- Poll
GET /v3/list-tweets?list_id=YOUR_ID at your desired interval.
Monitoring cost comparison:
| Approach | 50 accounts, 10-second polling | Requests/day |
|---|
Individual /user-tweets per account | 50 requests per cycle | 432,000 |
Single /list-tweets call | 1 request per cycle | 8,640 |
For more cost optimization patterns, see Optimizing API Usage.
Mining Communities for Audience Data
Communities are self-selected audiences. Extracting the member list gives you a pre-qualified group of people interested in a specific topic. For more audience discovery techniques, see Target Audience Discovery.
# Extract members of a DeFi community
members = get_community_members("COMMUNITY_ID", max_pages=20)
# Filter for high-value accounts
qualified = [
m for m in members
if m.get("followers_count", 0) >= 500
and m.get("tweets_count", 0) >= 50
]
print(f"Qualified members (500+ followers, 50+ tweets): {len(qualified)}")
# Analyze what the community talks about
tweets = get_community_tweets("COMMUNITY_ID", order="popular", max_pages=10)
# Extract top themes by looking at most-engaged posts
for t in sorted(tweets, key=lambda x: x.get("likes_count", 0), reverse=True)[:10]:
print(f" ({t['likes_count']} likes) {t['full_text'][:80]}...")
Finding Niche Experts via List Membership
Industry experts often appear on curated lists maintained by journalists, analysts, or organizations. If you find a list titled “AI Researchers” or “Crypto Founders” maintained by a credible curator, the member list is an expert-vetted roster:
# Get members of a curated expert list
experts = get_list_members("EXPERT_LIST_ID")
# Sort by follower count
experts.sort(key=lambda u: u.get("followers_count", 0), reverse=True)
print(f"Expert list: {len(experts)} members")
for u in experts[:10]:
print(f" @{u['username']} ({u['followers_count']:,}): {u.get('description', '')[:60]}")
Comparing Activity Across Multiple Communities
If your niche has several active communities, compare them to find where the most valuable conversations happen:
communities = {
"DeFi Builders": "1111111111",
"Crypto Trading": "2222222222",
"Web3 Developers": "3333333333",
}
for name, cid in communities.items():
members = get_community_members(cid, max_pages=3)
tweets = get_community_tweets(cid, order="popular", max_pages=3)
avg_likes = 0
if tweets:
avg_likes = sum(t.get("likes_count", 0) for t in tweets) / len(tweets)
print(f"{name}:")
print(f" Members extracted: {len(members)}")
print(f" Recent tweets: {len(tweets)}")
print(f" Avg likes/tweet: {avg_likes:.1f}\n")
If you are running a campaign that requires users to join a community, Sorsa provides a dedicated verification endpoint: POST /v3/check-community-member. It returns a simple boolean without needing to paginate through the full member list. See Marketing Campaign Verification for the complete workflow.
Exporting to CSV
Both member lists and tweet feeds can be exported using the same patterns from other guides:
import csv
def export_members_to_csv(members, output_file="community_members.csv"):
fields = ["id", "username", "display_name", "description",
"followers_count", "tweets_count", "verified", "location"]
with open(output_file, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=fields)
writer.writeheader()
for u in members:
writer.writerow({
"id": u.get("id", ""),
"username": u.get("username", ""),
"display_name": u.get("display_name", ""),
"description": (u.get("description") or "").replace("\n", " "),
"followers_count": u.get("followers_count", 0),
"tweets_count": u.get("tweets_count", 0),
"verified": u.get("verified", False),
"location": u.get("location", ""),
})
print(f"Exported {len(members)} members to {output_file}")
Next Steps