# X (Twitter) Engagement Scraper | $0.15/1K | Who Engaged (`feedminer/x-engagement-scraper`) Actor

Find out who amplified a post on X (Twitter). Export the accounts that reposted it, liked it, quoted it or replied to it, each with handle, name, bio, follower counts, verification and the text they wrote. The warmest lead list a launch can produce, as JSON, CSV or Excel. By FeedMiner.

- **URL**: https://apify.com/feedminer/x-engagement-scraper.md
- **Developed by:** [FeedMiner](https://apify.com/feedminer) (community)
- **Categories:** Social media, Lead generation, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.12 / 1,000 account returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

<div style="border-left:4px solid #1D9BF0;background:#F2F9FF;padding:14px 18px;border-radius:6px">
<strong>Find out who talked back to a post on X (Twitter).</strong> Everyone who quoted it and everyone who replied to it, each with handle, name, bio, follower count, verification and the text they wrote. One post in, the whole conversation around it out.
</div>

🗯️ **Quotes and replies in one run.** Both come out together, tagged by what each account did, with the text they wrote. Reposters and likers are not offered here: X serves those two lists to a real browser only, which we measured rather than assumed.

💸 **$0.15 per 1,000 accounts, down to $0.12 on the larger Apify plans.** The most visible tool on the store bills $0.40 per 1,000 plus $0.016 per post for reposters alone. No start fee, no per-post fee.

🎯 **The warmest list you will ever build.** Someone who replied to your launch or quoted it is a better lead than someone who follows you and never reacts. This is that list, with follower counts and bios on it.

🔓 **Nothing to connect.** Repliers and quote authors both come back on a run where you supplied nothing. No login, no cookie, no API key on your side.

#### Copy to your AI assistant

```
feedminer/x-engagement-scraper on Apify. Lists the accounts that engaged with an X (Twitter) post: quote authors and repliers. One row per account with id, userName, name, description, followers, following, isVerified, isBlueVerified, location, plus engagement (quotes|replies), tweetId, text, postUrl and engagedAt. Call ApifyClient("TOKEN").actor("feedminer/x-engagement-scraper").call(run_input={...}), then client.dataset(run["defaultDatasetId"]).list_items().items. Input: startUrls (string[] of post URLs or ids), engagements (string[] of quotes|replies), maxItems (int), sessions (array, optional). Full spec: GET https://api.apify.com/v2/acts/feedminer~x-engagement-scraper/builds/default (Bearer TOKEN) → inputSchema, actorDefinition.storages.dataset, readme. Token: https://console.apify.com/account/integrations
```

***

### <img src="https://apify-image-uploads-prod.s3.us-east-1.amazonaws.com/hoZ24gXinDHziMQKm-actor-3hbiY2nfMGfbNdh1w-DUuuMSYQpE-IMG_9471.jpeg" width="26" height="26" style="vertical-align:-4px;border-radius:6px"/> How to find who engaged with an X (Twitter) post

##### Basic: everyone who talked back to a post

```json
{
  "startUrls": ["https://x.com/elonmusk/status/1519480761749016577"],
  "engagements": ["replies", "quotes"],
  "maxItems": 2000
}
```

##### Replies only, with nothing to connect

```json
{
  "startUrls": ["https://x.com/elonmusk/status/1519480761749016577"],
  "engagements": ["replies"],
  "maxItems": 200
}
```

##### Who quoted a competitor's announcement

```json
{
  "startUrls": ["https://x.com/stripe/status/1234567890123456789"],
  "engagements": ["quotes"],
  "maxItems": 500
}
```

Quotes are where the opinions are. A repost is agreement, a quote is a comment.

##### Several posts in one job

```json
{
  "startUrls": [
    "https://x.com/yourcompany/status/1111111111111111111",
    "https://x.com/yourcompany/status/2222222222222222222"
  ],
  "engagements": ["quotes", "replies"],
  "maxItems": 4000
}
```

Every row carries `tweetId` and `engagement`, so one export covers a whole campaign and still splits per post and per kind.

***

### Input parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| `startUrls` | array |  | The posts to look at, as post URLs or ids |
| `engagements` | array | `['replies', 'quotes']` | Replies are served without an account. Quotes come from X's search index and need one. Reposters and likers are not offered: X serves their lists only to a real browser, measured twice with a signed in account |
| `maxItems` | integer | `1000` | Stop once this many engagements have been collected |

**Advanced**

| Parameter | Type | Default | Description |
|---|---|---|---|
| `sessions` | array |  | Optional. The Actor works without one. X accounts of your own, for anyone who would rather the run used accounts they control |
| `debugMode` | boolean | `false` | Verbose logs for support |

#### Coming from another engagement scraper

A single `tweetId` works, as do `tweetIds`, `tweetUrls`, `postUrls` and `urls`.

#### Nothing to connect

Paste post URLs and press Start. Repliers and quote authors both come back on a run where you supplied nothing.

If you would rather the run worked from accounts you own, the optional `sessions` field takes them.

***

### What data can you extract from post engagement?

| Field | Type | Description |
|---|---|---|
| `engagement` | string | What this account did: `quotes` or `replies` |
| `tweetId` | string | The post they engaged with |
| `userName` | string | Handle |
| `name` | string | Display name |
| `description` | string | Bio |
| `followers` `following` | integer | Audience size |
| `statusesCount` `mediaCount` `favouritesCount` | integer | Activity counters |
| `isVerified` `isBlueVerified` | boolean | Verification |
| `location` | string | Free text location |
| `twitterUrl` `profilePicture` | string | Profile links |
| `createdAt` | string | Account creation date, RFC 3339 |
| `text` | string | What they wrote |
| `postUrl` | string | A link to what they wrote |
| `engagedAt` | string | When they wrote it, RFC 3339 |

***

### Pricing: Pay Per Event (PPE)

| Event | Price |
|---|---|
| Account returned | $0.00015 |

That is **$0.15 per 1,000 accounts**, with no start fee and no charge for a run that returns nothing. The price steps down on its own for the larger Apify plans, to $0.14 and then $0.12 per 1,000.

***

##### What a run costs

| | |
|---|---|
| Everyone who replied to or quoted one launch post, 2,000 accounts | $0.30 |
| A campaign of ten posts, 20,000 accounts | $3.00 |

##### Free tier

The Apify free plan includes $5 of usage every month, which is roughly 33,000 accounts here. No card required.

### Advanced usage

**Score your own launches.** Export the repliers and quote authors of every launch post you made this year, count how many are verified and how many have more than 5,000 followers, and you have a reach report nobody had to compile by hand.

**Find the people who move a market.** The same handles quoting three competitors are the voices of your category. Sort by `followers`, keep the top hundred, that is your outreach list.

**Read the room before replying.** Quotes carry the text people wrote about a post. Sentiment on a launch is one export, not a week of scrolling.

**Cross with a follower export.** Pull an audience with X Follower Scraper, then pull the engagers here. Accounts in both lists are your active audience, the rest is dormant.

***

### Integrate X engagement data into your stack

**Python**

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("feedminer/x-engagement-scraper").call(run_input={
    "startUrls": ["https://x.com/yourcompany/status/1234567890123456789"],
    "engagements": ["quotes", "replies"],
    "maxItems": 3000,
})

rows = client.dataset(run["defaultDatasetId"]).list_items().items
reach = sum(r["followers"] for r in rows if r["engagement"] == "quotes")
print("quoted to roughly", reach, "followers")
```

**JavaScript**

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('feedminer/x-engagement-scraper').call({
    startUrls: ['https://x.com/stripe/status/1234567890123456789'],
    engagements: ['quotes'],
    maxItems: 500,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const critical = items.filter((i) => /but |however|disagree/i.test(i.text || ''));
```

**No code**

Send the dataset to Google Sheets, Airtable, Slack, Zapier, Make or n8n from the Integrations tab of the run.

***

### Performance

| Measure | Value |
|---|---|
| Accounts per page | 20, the same page size X's own web app requests |
| Parallelism | Up to six jobs at a time, a job being one post and one engagement kind |
| Partial results | Kept and delivered when a limit is reached |

***

### FAQ

**Can I get everyone who reposted or liked a post?**
Not here. X serves those two lists to a signed-in browser only, which we measured twice with an account rather than assumed. Replies and quotes are what X publishes, and the run walks them as far as `maxItems` asks, on a large post a deep but not unlimited list.

**Why do replies need nothing while quotes come from the search index?**
Because X publishes a post's conversation to anyone and serves its search index to signed-in sessions only. The run brings its own session for the quotes, so you supply nothing either way.

**Is a quote the same as a repost?**
No. A repost is a share with no comment, a quote adds one. Quotes carry the text and are listed here; reposts are not.

**Do I get the reply text?**
Yes, in `text`, with a link in `postUrl`.

**What about a deleted post?**
The run reports it and moves to the next input instead of failing.

**Can I run this on someone else's post?**
Yes, any public post. That is what makes it a competitive intelligence tool and not just an analytics one.

**How do I avoid counting the same account twice?**
Rows are deduplicated per post and per engagement kind. An account that both replied and quoted appears once for each, which is deliberate: those are two different signals.

**Does it work on a thread?**
Point it at any post in the thread. Each post has its own engagement.

***

### Support

A post that will not open, an engagement kind you need, a list that stops early: write from the actor page.

***

### Legal compliance

This actor reads engagement that X publishes on public posts. It does not access private accounts, protected posts or direct messages. Personal data in the output is subject to GDPR, CCPA and similar regimes: collect what you have a lawful basis to collect, keep it only as long as you need it, and honour deletion requests.

***

**FeedMiner** · Fast, honestly priced scrapers, kept alive when platforms change.

[X Tweet Scraper](https://apify.com/feedminer/x-tweet-scraper) · [X Profile Scraper](https://apify.com/feedminer/x-profile-scraper) · [X Follower Scraper](https://apify.com/feedminer/x-follower-scraper) · [X Advanced Search Scraper](https://apify.com/feedminer/x-advanced-search-scraper) · [X Media Scraper](https://apify.com/feedminer/x-media-scraper) · [X Mentions Monitor](https://apify.com/feedminer/x-mentions-scraper) · X Engagement Scraper · [X Likes and Reposts Scraper](https://apify.com/feedminer/x-signals-scraper) · [X Trends Scraper](https://apify.com/feedminer/x-trends-scraper) · [All FeedMiner Actors](https://apify.com/feedminer)

# Actor input Schema

## `startUrls` (type: `array`):

The posts to look at, as post URLs or ids.

## `engagements` (type: `array`):

Replies are served without an account. Quotes come from X's search index and need one. Reposters and likers are not offered: X serves their lists only to a real browser, measured twice with a signed in account.

## `maxItems` (type: `integer`):

Stop once this many engagements have been collected.

## `sessions` (type: `array`):

Optional. The Actor works without one. X accounts of your own, for anyone who would rather the run used accounts they control.

## `debugMode` (type: `boolean`):

Verbose logs for support.

## Actor input object example

```json
{
  "startUrls": [
    "https://x.com/elonmusk/status/1519480761749016577"
  ],
  "engagements": [
    "replies",
    "quotes"
  ],
  "maxItems": 1000,
  "sessions": [
    {
      "label": "account-1",
      "authToken": "",
      "ct0": ""
    }
  ],
  "debugMode": false
}
```

# Actor output Schema

## `engagers` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "startUrls": [
        "https://x.com/elonmusk/status/1519480761749016577"
    ],
    "maxItems": 1000,
    "sessions": [
        {
            "label": "account-1",
            "authToken": "",
            "ct0": ""
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("feedminer/x-engagement-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "startUrls": ["https://x.com/elonmusk/status/1519480761749016577"],
    "maxItems": 1000,
    "sessions": [{
            "label": "account-1",
            "authToken": "",
            "ct0": "",
        }],
}

# Run the Actor and wait for it to finish
run = client.actor("feedminer/x-engagement-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "startUrls": [
    "https://x.com/elonmusk/status/1519480761749016577"
  ],
  "maxItems": 1000,
  "sessions": [
    {
      "label": "account-1",
      "authToken": "",
      "ct0": ""
    }
  ]
}' |
apify call feedminer/x-engagement-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,feedminer/x-engagement-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/Nwwwpa8wQsBawrqaz/builds/0keW2Z3sWdbcUMPUf/openapi.json
