Skip to main content

X Lists & Communities

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:
EndpointMethodWhat it returns
GET /v3/list-membersGETUser profiles of accounts in the list
GET /v3/list-followersGETUser profiles of accounts following the list
GET /v3/list-tweetsGETRecent 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]}")
ParameterTypeRequiredDescription
list_idstringYesThe 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")
ParameterTypeRequiredDescription
list_linkstringYesThe list URL or ID.
next_cursorstringNoPagination cursor.

Getting List Tweets

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]}...")
ParameterTypeRequiredDescription
list_idstringYesThe numeric List ID.
cursorstringNoPagination 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:
EndpointMethodWhat it returns
POST /v3/community-membersPOSTUser profiles of community members
POST /v3/community-tweetsPOSTTweets posted within the community
POST /v3/community-search-tweetsPOSTTweets 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.

Getting Community Members

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")
ParameterTypeRequiredDescription
community_linkstringYesCommunity ID or full URL.
next_cursorstringNoPagination cursor.

Getting Community Tweets

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]}...")
ParameterTypeRequiredDescription
community_idstringYesThe numeric Community ID.
order_bystringNo"latest" (default) or "popular".
next_cursorstringNoPagination cursor.

Searching Tweets Within a Community

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'")
ParameterTypeRequiredDescription
community_linkstringYesCommunity URL or ID.
querystringYesSearch keyword.
order_bystringNo"popular" or "latest".
next_cursorstringNoPagination 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:
  1. Go to X Lists and create a new public list (private lists cannot be accessed via API).
  2. Add the accounts you want to track (up to 5,000).
  3. Copy the List ID from the URL.
  4. Poll GET /v3/list-tweets?list_id=YOUR_ID at your desired interval.
Monitoring cost comparison:
Approach50 accounts, 10-second pollingRequests/day
Individual /user-tweets per account50 requests per cycle432,000
Single /list-tweets call1 request per cycle8,640

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:
# 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")

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