Skip to main content

Tweet Engagement

Every tweet on X generates three types of public engagement: comments (replies), quote tweets, and retweets. The aggregate counts are visible on the tweet itself, but the actual people and content behind those numbers are not. Sorsa provides dedicated endpoints to extract all three: who replied and what they said, who quoted the tweet and what they added, and who retweeted it. This guide covers how to retrieve a tweet’s full engagement data, from a high-level metrics snapshot down to the individual replies, quotes, and retweeters.
Note: For a fuller walkthrough with extra analysis examples and end-to-end workflows, see Twitter Engagement API: Get Replies, Quotes & Retweeters on the blog.

Starting Point: Get a Tweet’s Metrics

Before drilling into individual engagement, you often want the overview. The /tweet-info endpoint returns the full tweet object including all engagement counters.

Simplest Example

curl -X POST https://api.sorsa.io/v3/tweet-info \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tweet_link": "https://x.com/elonmusk/status/1234567890"}'
import requests

API_KEY = "YOUR_API_KEY"

def get_tweet(tweet_link):
    resp = requests.post(
        "https://api.sorsa.io/v3/tweet-info",
        headers={"ApiKey": API_KEY, "Content-Type": "application/json"},
        json={"tweet_link": tweet_link},
    )
    resp.raise_for_status()
    return resp.json()


tweet = get_tweet("https://x.com/elonmusk/status/1234567890")

print(f"Text: {tweet['full_text'][:100]}...")
print(f"Likes:    {tweet.get('likes_count', 0):,}")
print(f"Retweets: {tweet.get('retweet_count', 0):,}")
print(f"Quotes:   {tweet.get('quote_count', 0):,}")
print(f"Replies:  {tweet.get('reply_count', 0):,}")
print(f"Views:    {tweet.get('view_count', 0):,}")
print(f"Bookmarks:{tweet.get('bookmark_count', 0):,}")
For multiple tweets at once, use /tweet-info-bulk with up to 100 tweet links per request (see Optimizing API Usage).

Comments (Replies)

Endpoint: POST /v3/comments Returns the replies posted under a specific tweet. Each page contains up to 20 comments, and each comment is a full tweet object with its own engagement metrics and author profile.

Simplest Example

def get_comments(tweet_link):
    resp = requests.post(
        "https://api.sorsa.io/v3/comments",
        headers={"ApiKey": API_KEY, "Content-Type": "application/json"},
        json={"tweet_link": tweet_link},
    )
    resp.raise_for_status()
    return resp.json()

data = get_comments("https://x.com/elonmusk/status/1234567890")
for comment in data.get("tweets", []):
    print(f"@{comment['user']['username']}: {comment['full_text'][:80]}")

Parameters

ParameterTypeRequiredDescription
tweet_linkstringYesFull URL of the tweet.
next_cursorstringNoPagination cursor for fetching more comments.

Paginating Through All Comments

Tweets with hundreds of replies require pagination. The pattern is the same cursor-based loop used across all Sorsa endpoints:
import time

def get_all_comments(tweet_link, max_pages=20):
    """Fetch all comments under a tweet with pagination."""
    all_comments = []
    next_cursor = None

    for page in range(max_pages):
        body = {"tweet_link": tweet_link}
        if next_cursor:
            body["next_cursor"] = next_cursor

        resp = requests.post(
            "https://api.sorsa.io/v3/comments",
            headers={"ApiKey": API_KEY, "Content-Type": "application/json"},
            json=body,
        )
        resp.raise_for_status()
        data = resp.json()

        comments = data.get("tweets", [])
        all_comments.extend(comments)

        next_cursor = data.get("next_cursor")
        if not next_cursor:
            break
        time.sleep(0.1)

    return all_comments


comments = get_all_comments("https://x.com/elonmusk/status/1234567890")
print(f"Collected {len(comments)} comments")
Each comment is a full tweet object: text, engagement metrics, and author profile. Common patterns include sorting by likes_count to find the most-engaged-with replies, filtering on ? to extract questions, and feeding full_text into a sentiment classifier.
# Find the most-liked comments
top_comments = sorted(comments, key=lambda c: c.get("likes_count", 0), reverse=True)

for c in top_comments[:5]:
    print(f"@{c['user']['username']} ({c['likes_count']} likes): {c['full_text'][:80]}")

Quote Tweets

Endpoint: POST /v3/quotes Returns tweets that quoted (retweeted with comment) a specific tweet. Like comments, each quote is a full tweet object: you get the added commentary, engagement metrics, and author profile.

Simplest Example

def get_quotes(tweet_link):
    resp = requests.post(
        "https://api.sorsa.io/v3/quotes",
        headers={"ApiKey": API_KEY, "Content-Type": "application/json"},
        json={"tweet_link": tweet_link},
    )
    resp.raise_for_status()
    return resp.json()

data = get_quotes("https://x.com/elonmusk/status/1234567890")
for quote in data.get("tweets", []):
    print(f"@{quote['user']['username']} quoted: {quote['full_text'][:80]}")

Parameters

ParameterTypeRequiredDescription
tweet_linkstringYesFull URL of the original tweet.
next_cursorstringNoPagination cursor.

Paginating Through All Quotes

def get_all_quotes(tweet_link, max_pages=20):
    """Fetch all quote tweets of a specific tweet."""
    all_quotes = []
    next_cursor = None

    for page in range(max_pages):
        body = {"tweet_link": tweet_link}
        if next_cursor:
            body["next_cursor"] = next_cursor

        resp = requests.post(
            "https://api.sorsa.io/v3/quotes",
            headers={"ApiKey": API_KEY, "Content-Type": "application/json"},
            json=body,
        )
        resp.raise_for_status()
        data = resp.json()

        quotes = data.get("tweets", [])
        all_quotes.extend(quotes)

        next_cursor = data.get("next_cursor")
        if not next_cursor:
            break
        time.sleep(0.1)

    return all_quotes
Since each quote carries both author profile and added text, you can rank quoters by reach:
quotes = get_all_quotes("https://x.com/brand/status/1234567890")

# Find quotes that reached the largest audiences
quotes.sort(key=lambda q: q["user"].get("followers_count", 0), reverse=True)

for q in quotes[:5]:
    u = q["user"]
    print(f"@{u['username']} ({u['followers_count']:,} followers)")
    print(f"  \"{q['full_text'][:80]}...\"\n")

Retweeters

Endpoint: POST /v3/retweeters Returns the users who retweeted a specific tweet. Unlike /comments and /quotes, this endpoint returns a UsersResponse (array of user profiles), not a TweetsResponse. You get the retweeters’ profiles, not tweet objects.

Simplest Example

def get_retweeters(tweet_link):
    resp = requests.post(
        "https://api.sorsa.io/v3/retweeters",
        headers={"ApiKey": API_KEY, "Content-Type": "application/json"},
        json={"tweet_link": tweet_link},
    )
    resp.raise_for_status()
    return resp.json()

data = get_retweeters("https://x.com/elonmusk/status/1234567890")
for user in data.get("users", []):
    print(f"@{user['username']} ({user['followers_count']} followers) retweeted")

Parameters

ParameterTypeRequiredDescription
tweet_linkstringYesFull URL of the tweet.
next_cursorstringNoPagination cursor.

Response Format Difference

This is the key distinction to remember across the three engagement endpoints:
EndpointReturnsResponse keyContains
/commentsTweetstweetsFull tweet objects (text + author)
/quotesTweetstweetsFull tweet objects (text + author)
/retweetersUsersusersUser profile objects only
Retweets do not have their own text (a retweet is just a redistribution of the original), so the endpoint returns the profile of each retweeter instead.

Paginating Through All Retweeters

def get_all_retweeters(tweet_link, max_pages=20):
    """Fetch all users who retweeted a tweet."""
    all_users = []
    next_cursor = None

    for page in range(max_pages):
        body = {"tweet_link": tweet_link}
        if next_cursor:
            body["next_cursor"] = next_cursor

        resp = requests.post(
            "https://api.sorsa.io/v3/retweeters",
            headers={"ApiKey": API_KEY, "Content-Type": "application/json"},
            json=body,
        )
        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
Since you get full user profiles, you can quantify the reach of the amplification:
retweeters = get_all_retweeters("https://x.com/brand/status/1234567890")

total_reach = sum(u.get("followers_count", 0) for u in retweeters)
verified_count = sum(1 for u in retweeters if u.get("verified"))

print(f"Retweeters: {len(retweeters)}")
print(f"Combined follower reach: {total_reach:,}")
print(f"Verified retweeters: {verified_count}")

Full Engagement Breakdown for a Single Tweet

Combining all three endpoints gives you a complete picture of a tweet’s performance:
def full_engagement_report(tweet_link):
    """Generate a complete engagement report for a single tweet."""

    tweet = get_tweet(tweet_link)
    print(f"Tweet by @{tweet['user']['username']}:")
    print(f"  \"{tweet['full_text'][:100]}...\"")
    print(f"  Likes: {tweet.get('likes_count', 0):,} | "
          f"Views: {tweet.get('view_count', 0):,}")
    print()

    comments = get_all_comments(tweet_link, max_pages=10)
    print(f"Comments: {len(comments)}")
    if comments:
        top_comment = max(comments, key=lambda c: c.get("likes_count", 0))
        print(f"  Most liked: @{top_comment['user']['username']} "
              f"({top_comment['likes_count']} likes)")
        print(f"  \"{top_comment['full_text'][:80]}...\"")
    print()

    quotes = get_all_quotes(tweet_link, max_pages=10)
    print(f"Quotes: {len(quotes)}")
    if quotes:
        biggest_quoter = max(quotes, key=lambda q: q["user"].get("followers_count", 0))
        print(f"  Highest reach: @{biggest_quoter['user']['username']} "
              f"({biggest_quoter['user']['followers_count']:,} followers)")
        print(f"  \"{biggest_quoter['full_text'][:80]}...\"")
    print()

    retweeters = get_all_retweeters(tweet_link, max_pages=10)
    total_reach = sum(u.get("followers_count", 0) for u in retweeters)
    print(f"Retweeters: {len(retweeters)}")
    print(f"  Combined reach: {total_reach:,} followers")
    if retweeters:
        top_rt = max(retweeters, key=lambda u: u.get("followers_count", 0))
        print(f"  Biggest amplifier: @{top_rt['username']} "
              f"({top_rt['followers_count']:,} followers)")

    return {
        "tweet": tweet,
        "comments": comments,
        "quotes": quotes,
        "retweeters": retweeters,
    }


report = full_engagement_report("https://x.com/brand/status/1234567890")

Sample Output

Tweet by @brand:
  "We're excited to announce our Series B funding round of $50M..."
  Likes: 2,847 | Views: 892,000

Comments: 156
  Most liked: @tech_journalist (89 likes)
  "Congrats! What's the plan for international expansion?..."

Quotes: 43
  Highest reach: @vc_partner (284,000 followers)
  "This team has been on our radar for two years. Well deserved...."

Retweeters: 312
  Combined reach: 4,218,000 followers
  Biggest amplifier: @industry_leader (892,000 followers)

Analyzing Multiple Tweets (Batch Pattern)

When you need engagement data for a set of tweets (e.g., all posts from a campaign), fetch the tweet list first via /user-tweets or /search-tweets, then drill into each one:
def compare_tweet_engagement(tweet_links):
    """Compare engagement breakdown across multiple tweets."""
    results = []

    for link in tweet_links:
        tweet = get_tweet(link)
        comments = get_all_comments(link, max_pages=3)
        quotes = get_all_quotes(link, max_pages=3)
        retweeters = get_all_retweeters(link, max_pages=3)

        rt_reach = sum(u.get("followers_count", 0) for u in retweeters)

        results.append({
            "text": tweet["full_text"][:60],
            "likes": tweet.get("likes_count", 0),
            "comments": len(comments),
            "quotes": len(quotes),
            "retweets": len(retweeters),
            "retweet_reach": rt_reach,
        })
        time.sleep(0.5)

    print(f"{'Tweet':<62} {'Likes':>6} {'Cmts':>5} {'Qts':>4} {'RTs':>4} {'RT Reach':>10}")
    print("-" * 100)
    for r in results:
        print(f"{r['text']:<62} {r['likes']:>6} {r['comments']:>5} "
              f"{r['quotes']:>4} {r['retweets']:>4} {r['retweet_reach']:>10,}")

    return results
Tip: If you just need the aggregate metrics for many tweets without drilling into individual comments/quotes/retweeters, use /tweet-info-bulk to fetch up to 100 tweets in a single request. See Optimizing API Usage for more batch patterns.

Exporting Engagement Data to CSV

import csv

def export_comments_to_csv(comments, output_file="comments.csv"):
    fields = [
        "comment_id", "created_at", "full_text", "likes", "retweets",
        "author_username", "author_followers", "author_verified",
    ]
    with open(output_file, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=fields)
        writer.writeheader()
        for c in comments:
            u = c.get("user", {})
            writer.writerow({
                "comment_id": c["id"],
                "created_at": c["created_at"],
                "full_text": c["full_text"],
                "likes": c.get("likes_count", 0),
                "retweets": c.get("retweet_count", 0),
                "author_username": u.get("username", ""),
                "author_followers": u.get("followers_count", 0),
                "author_verified": u.get("verified", False),
            })
    print(f"Exported {len(comments)} comments to {output_file}")
The same pattern works for quotes (they are also tweet objects). For retweeters, export user fields instead of tweet fields.

Verification Endpoints: Did a Specific User Engage?

If you need to check whether a particular user commented on, quoted, or retweeted a tweet (common in campaign and giveaway verification), Sorsa provides dedicated verification endpoints that return a simple yes/no answer without paginating through the full list:
  • /check-comment: did a specific user reply to the tweet?
  • /check-quoted: did they quote it?
  • /check-retweet: did they retweet it?
These are covered in depth in the Marketing Campaign Verification guide.

Next Steps

  • Search Tweets: find tweets by keyword, then drill into their engagement.
  • Track Mentions: monitor mentions of your brand, then analyze engagement on the most-discussed ones.
  • Competitor Analysis: compare engagement patterns across competitor content.
  • Historical Data: retrieve old tweets and analyze how their engagement played out.
  • Marketing Campaign Verification: verify that specific users commented on or retweeted a tweet.
  • API Reference: full specification for /comments, /quotes, /retweeters, /tweet-info, /tweet-info-bulk.