Skip to main content

Tweet Engagement: Comments, Quotes, and Retweets

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 - unless you use an API. 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.

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). Now let’s look at who is behind each of those numbers.

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

What You Can Do with Comment Data

Each comment is a full tweet object, so you have the text, engagement metrics, and author profile. This unlocks several analysis patterns: Sentiment analysis. Feed the full_text of each comment into an NLP classifier to gauge whether replies are positive, negative, or neutral. A tweet with 500 replies that are 80% negative tells a very different story than one with 500 positive replies. Identify top commenters. Sort by likes_count to find the most-engaged-with replies. These are the voices that shaped the conversation. Extract questions. Filter comments containing ”?” to find questions your audience is asking - useful for FAQ generation, content ideas, and customer support detection.
# Find the most-liked comments
top_comments = sorted(comments, key=lambda c: c.get("likes_count", 0), reverse=True)

print("Top 5 comments by likes:")
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

Why Quote Tweets Matter More Than Retweets

A retweet is passive amplification - the user pressed a button. A quote tweet is active engagement - the user added their own take, and that take is visible to their entire audience. Quotes often contain the most valuable signal: endorsements, criticisms, counterarguments, and derivative ideas. For content analysis and PR monitoring, quote tweets are where the real conversation happens.
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)

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

Retweets (Who Retweeted)

Endpoint: POST /v3/retweets Returns the users who retweeted a specific tweet. Note: 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/retweets",
        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:
EndpointReturnsResponse keyContains
/commentsTweetstweetsFull tweet objects (text + author)
/quotesTweetstweetsFull tweet objects (text + author)
/retweetsUsersusersUser 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/retweets",
            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

Analyzing Retweeter Profiles

Since you get full user profiles, you can analyze who amplified the tweet:
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 how a tweet performed - not just the numbers, but the people and content behind them:
def full_engagement_report(tweet_link):
    """Generate a complete engagement report for a single tweet."""

    # Get tweet metrics
    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
    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
    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
    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 comparison
    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
This is useful for identifying which tweets in a series performed best and understanding why - did success come from comments (conversation), quotes (endorsement/debate), or retweets (amplification)?

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.

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.
  • Campaign Verification - verify that specific users commented on or retweeted a tweet.
  • API Reference - full specification for /comments, /quotes, /retweets, /tweet-info, /tweet-info-bulk.