> ## 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.

# Tweet Engagement

# 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](https://api.sorsa.io/blog/twitter-engagement-api) 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

```bash theme={null}
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"}'
```

```python theme={null}
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):,}")
```

The `tweet_link` field accepts either a full tweet URL or just the numeric tweet ID. For multiple tweets at once, use `/tweet-info-bulk` with up to 100 tweet links per request (see [Optimizing API Usage](https://docs.sorsa.io/optimizing-api-usage)).

> **Tip:** New here? Every account starts with 100 free requests (no card, no expiry). You can also run any endpoint on this page without writing code in the [API Playground](https://api.sorsa.io/playground).

***

## 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

```python theme={null}
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

| Parameter     | Type   | Required | Description                                                     |
| :------------ | :----- | :------- | :-------------------------------------------------------------- |
| `tweet_link`  | string | Yes      | Full URL of the tweet, or just the tweet ID.                    |
| `order_by`    | string | No       | Sort order: `"Relevance"` (default), `"Recency"`, or `"Likes"`. |
| `next_cursor` | string | No       | Pagination cursor for fetching more comments.                   |

Set `order_by` to `"Likes"` to have the API rank replies by engagement server-side. This is more efficient than fetching everything and sorting locally when you only need the top few replies, since page one already holds the most-liked 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:

```python theme={null}
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.

```python theme={null}
# 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

```python theme={null}
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

| Parameter     | Type   | Required | Description                                           |
| :------------ | :----- | :------- | :---------------------------------------------------- |
| `tweet_link`  | string | Yes      | Full URL of the original tweet, or just the tweet ID. |
| `next_cursor` | string | No       | Pagination cursor.                                    |

### Paginating Through All Quotes

```python theme={null}
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:

```python theme={null}
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, newest first. 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

```python theme={null}
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

| Parameter     | Type   | Required | Description                                  |
| :------------ | :----- | :------- | :------------------------------------------- |
| `tweet_link`  | string | Yes      | Full URL of the tweet, or just the tweet ID. |
| `next_cursor` | string | No       | Pagination cursor.                           |

### Response Format Difference

This is the key distinction to remember across the three engagement endpoints:

| Endpoint      | Returns | Response key | Contains                           |
| :------------ | :------ | :----------- | :--------------------------------- |
| `/comments`   | Tweets  | `tweets`     | Full tweet objects (text + author) |
| `/quotes`     | Tweets  | `tweets`     | Full tweet objects (text + author) |
| `/retweeters` | Users   | `users`      | User 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

```python theme={null}
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:

```python theme={null}
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. Because it paginates every engagement type, this fans out into many requests (each page is one request against your quota), so reserve it for tweets you specifically need a full breakdown on:

```python theme={null}
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

```text theme={null}
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:

```python theme={null}
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](https://docs.sorsa.io/optimizing-api-usage) for more batch patterns.

***

## Exporting Engagement Data to CSV

```python theme={null}
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](https://docs.sorsa.io/Marketing-Campaign-Verification) guide.

***

## Next Steps

* [Search Tweets](https://docs.sorsa.io/search-tweets): find tweets by keyword, then drill into their engagement.
* [Track Mentions](https://docs.sorsa.io/search-mentions): monitor mentions of your brand, then analyze engagement on the most-discussed ones.
* [Competitor Analysis](https://docs.sorsa.io/Competitor-Analysis): compare engagement patterns across competitor content.
* [Historical Data](https://docs.sorsa.io/historical-data): retrieve old tweets and analyze how their engagement played out.
* [Marketing Campaign Verification](https://docs.sorsa.io/Marketing-Campaign-Verification): verify that specific users commented on or retweeted a tweet.
* [API Reference](https://docs.sorsa.io/api-reference-guide): full specification for `/comments`, `/quotes`, `/retweeters`, `/tweet-info`, `/tweet-info-bulk`.
