# Twitter/X Engaged Audience Exporter · Replies + Retweeters (`data-slayer/twitter-engaged-audience-exporter`) Actor

Build a deduplicated audience from public tweet replies and retweets, with explicit relationship edges, bounded profile enrichment, JSON/CSV exports, and honest partial or empty summaries.

- **URL**: https://apify.com/data-slayer/twitter-engaged-audience-exporter.md
- **Developed by:** [Data Slayer](https://apify.com/data-slayer) (community)
- **Categories:** Social media, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.45 / 1,000 unique engaged people

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

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

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Twitter/X Engaged Audience Exporter

Turn public tweet replies and retweets into a deduplicated audience plus explicit person-to-tweet relationship edges for research, outreach preparation, CRM imports, and engagement analysis.

### Watch the demo

YouTube video coming soon.

### What this Actor does

Paste up to 25 public X/Twitter post URLs or numeric tweet IDs. The Actor checks replies, retweets, or both, normalizes the public account details it can retrieve, collapses the same person across posts and engagement types, and writes two typed record kinds:

- `person`: one row per unique public account found during the run.
- `engagement_edge`: one row per unique account-to-post reply or retweet relationship.

This is different from a raw comments export. A person who replied twice and retweeted the same post appears once in the audience table, while the distinct relationships remain available in the edge table.

### Supported engagement types

| Type | Included | Notes |
| --- | --- | --- |
| Replies | Yes | Returns public reply authors and, when available, reply text and thread identifiers. |
| Retweets | Yes | Returns public retweeter accounts. |
| Quotes | No | Quote-author coverage is not part of this version. |
| Likes | No | Liker lists are not part of this version. |

The Actor reports complete, partial, empty, unavailable, and failed tweet outcomes separately. “Complete” means all selected routes reached a normal stopping condition within the configured limits; it is not a claim that X exposes every historical engagement.

### Input

| Field | Type | Default | Limits | Purpose |
| --- | --- | --- | --- | --- |
| `tweetUrls` | string\[] | required | 1–25 | Public `x.com` or `twitter.com` status URLs, or numeric tweet IDs. Duplicate IDs are processed once. |
| `engagementTypes` | string\[] | `reply`, `retweet` | one or both | Select the relationship types to collect. |
| `maxPeoplePerTweet` | integer | `250` | 1–1,000 | Bounds each selected engagement type for each input tweet. |
| `maxUniquePeople` | integer | `1000` | 1–5,000 | Global cap after cross-post deduplication. |
| `includeProfileDetails` | boolean | `false` | — | Add a bounded profile snapshot to unique-person rows. |
| `maxProfileLookups` | integer | `100` | 1–500 | Maximum profile enrichment attempts when enrichment is enabled. |

Free-plan runs are limited to one tweet, 50 unique people, and no profile enrichment. Paid-plan limits follow the values above.

```json
{
  "tweetUrls": [
    "https://x.com/apify/status/2021770553154285890",
    "2021770553154285891"
  ],
  "engagementTypes": ["reply", "retweet"],
  "maxPeoplePerTweet": 250,
  "maxUniquePeople": 1000,
  "includeProfileDetails": false,
  "maxProfileLookups": 100
}
```

### Output

The default dataset contains only paid value records. Run status and diagnostics are stored in the default key-value store under `OUTPUT`; status records are never inserted as billable dataset items.

#### Unique-person row

```json
{
  "recordType": "person",
  "personKey": "id:44196397",
  "userId": "44196397",
  "username": "example_user",
  "name": "Example User",
  "bio": "Public profile biography",
  "profileUrl": "https://x.com/example_user",
  "profileImageUrl": "https://pbs.twimg.com/profile_images/example.jpg",
  "followersCount": 4200,
  "followingCount": 380,
  "verified": false,
  "blueVerified": false,
  "engagementTypes": ["reply", "retweet"],
  "sourceTweetIds": ["2021770553154285890"],
  "sourceTweetUrls": ["https://x.com/i/status/2021770553154285890"],
  "edgeCount": 2,
  "firstEngagedAt": "2026-09-20T11:23:45Z",
  "lastEngagedAt": "2026-09-20T11:23:45Z",
  "profile": null,
  "enrichmentStatus": "not_requested",
  "collectedAt": "2026-09-21T00:00:00Z"
}
```

#### Engagement-edge row

```json
{
  "recordType": "engagement_edge",
  "edgeId": "4e3a8ca84184ce3ea62d8d02be9f14ea",
  "sourceTweetId": "2021770553154285890",
  "sourceTweetUrl": "https://x.com/i/status/2021770553154285890",
  "personKey": "id:44196397",
  "userId": "44196397",
  "username": "example_user",
  "engagementType": "reply",
  "engagementTweetId": "2021770553154285999",
  "engagementTweetUrl": "https://x.com/i/status/2021770553154285999",
  "parentTweetId": "2021770553154285890",
  "conversationId": "2021770553154285890",
  "text": "Useful launch notes—thanks for sharing.",
  "engagedAt": "2026-09-20T11:23:45Z",
  "replyDepth": 1,
  "collectedAt": "2026-09-21T00:00:00Z"
}
```

`null` means the field was not available for that account or relationship. Counts are numbers when available. JSON arrays remain arrays; CSV exports flatten nested fields according to Apify’s export rules.

### Run summary and failure behavior

Open the `OUTPUT` record in the run’s key-value store to see:

- accepted and duplicate input counts;
- complete, partial, empty, and failed tweet counts;
- successful and failed engagement-type checks;
- unique people and edges found versus saved;
- deduplicated edge count;
- profile enrichment outcomes;
- reached limits and stable functional error codes.

A private, deleted, or unavailable tweet is not presented as a successful empty result. If one selected engagement type works and another does not, the tweet is marked `partial` and usable records from the successful type remain available. Transient rate limits, timeouts, and service errors receive bounded retries. Repeated cursors terminate safely.

### Pricing

This Actor uses pay-per-event pricing:

- one Actor-start event per run;
- one tweet-scan event only when at least one selected engagement source is successfully checked, including a valid empty result;
- one unique-person event per saved `person` row;
- one edge event per saved `engagement_edge` row;
- one profile-enrichment event only when optional profile details are successfully returned and added.

Failed lookups and status summaries are not billed as dataset results. Use Apify’s maximum-charge setting plus `maxPeoplePerTweet`, `maxUniquePeople`, and `maxProfileLookups` to control spend.

### Common workflows

- Build a deduplicated launch-engager list from several campaign tweets.
- Join reply text to public account identities for sentiment or moderation analysis.
- Separate people who replied from people who retweeted.
- Load unique people into a CRM while retaining auditable source-post edges.
- Schedule repeated exports and compare snapshots downstream using stable tweet, user, and edge IDs.

### Limitations and responsible use

- Only public data that is available at run time can be returned.
- Coverage can vary by post age, visibility, account privacy, deletion, and platform behavior.
- Limits prevent unbounded collection; a successful bounded run is not a completeness guarantee.
- This version does not return likes/likers or quote authors.
- This Actor is independent and is not affiliated with or endorsed by X Corp.
- Public profile and engagement data can still be personal data. You are responsible for a lawful purpose, data minimization, retention, and honoring applicable privacy and platform rules.

### API and automation

Run the Actor from Apify Console, the Apify API, schedules, webhooks, or integrations. Results are available as JSON, CSV, Excel, and other dataset export formats supported by Apify. Filter `recordType == "person"` for the deduplicated audience and `recordType == "engagement_edge"` for the relationship graph.

### Support

Open an issue on the Actor page with the run ID, the affected tweet ID, and the functional error code from `OUTPUT`. Do not post private credentials or personal access tokens.

### FAQ

**How much does it cost to run this Actor?**
Pricing is listed in the Pricing section above, charged per row returned. You only pay for the rows
the Actor actually produces, so a small test run costs cents.

**Do I need cookies or a login?**
No. This Actor reads public data only - no cookies, no account, no browser automation.

**Can I schedule it?**
Yes. Run it from the Apify API, on a schedule, or via a webhook, and export results as JSON, CSV or Excel.

**What if I need a slightly different output?**
Open an issue on the Actor's Issues tab describing the shape you need.

### Related actors

More Twitter actors from the same portfolio. Apify only auto-recommends actors in the same category, so here are the rest of ours:

| Actor |
|---|
| [Twitter/X Comments Scraper · No Cookies](https://apify.com/data-slayer/twitter-comments) |
| [Twitter/X Community Members Scraper · No Cookies](https://apify.com/data-slayer/twitter-community-members) |
| [Twitter/X Followers Scraper · No Cookies](https://apify.com/data-slayer/twitter-followers) |
| [Twitter/X Following Scraper · Public Profiles](https://apify.com/data-slayer/twitter-followings) |
| [Twitter/X List Members Scraper · No Cookies](https://apify.com/data-slayer/twitter-list-members) |
| [Twitter/X Profile Scraper · Bulk Handles, URLs & IDs](https://apify.com/data-slayer/twitter-user) |
| [Twitter/X Search Scraper · Small Jobs & Advanced Queries](https://apify.com/data-slayer/twitter-search) |
| [Twitter/X Trends Scraper · No Cookies](https://apify.com/data-slayer/twitter-trends-by-location) |
| [Twitter/X Tweet Details Scraper · URL or ID](https://apify.com/data-slayer/twitter-tweet-details) |
| [Twitter/X Tweets Scraper · No Cookies](https://apify.com/data-slayer/twitter-user-tweets) |

# Actor input Schema

## `tweetUrls` (type: `array`):

One to 25 public x.com or twitter.com status URLs, or numeric tweet IDs. Duplicate IDs are processed once.

## `engagementTypes` (type: `array`):

Collect reply authors, retweeters, or both. Likes and quote authors are not included.

## `maxPeoplePerTweet` (type: `integer`):

Stop collecting each selected engagement type after this many usable people for a tweet.

## `maxUniquePeople` (type: `integer`):

Global cap after deduplicating the same account across tweets and engagement types.

## `includeProfileDetails` (type: `boolean`):

Add a bounded profile snapshot to unique-person rows. Billed only when profile details are returned.

## `maxProfileLookups` (type: `integer`):

Maximum unique people to enrich when profile enrichment is enabled.

## Actor input object example

```json
{
  "tweetUrls": [
    "https://x.com/apify/status/2021770553154285890"
  ],
  "engagementTypes": [
    "reply",
    "retweet"
  ],
  "maxPeoplePerTweet": 250,
  "maxUniquePeople": 1000,
  "includeProfileDetails": false,
  "maxProfileLookups": 100
}
```

# Actor output Schema

## `results` (type: `string`):

One dataset row per unique engaged person or person-to-tweet engagement edge.

## `output` (type: `string`):

A typed summary is stored in the default key-value store under OUTPUT. Status records are never added to the paid dataset.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("data-slayer/twitter-engaged-audience-exporter").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("data-slayer/twitter-engaged-audience-exporter").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 '{}' |
apify call data-slayer/twitter-engaged-audience-exporter --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,data-slayer/twitter-engaged-audience-exporter"
        }
    }
}
```

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/8xzCgfpzLE3LaeSPf/builds/odCrQOidajo9mOOPy/openapi.json
