# X Post, Reply & Profile Lookup by Link or ID (`vexaloom-labs/x-post-reply-and-profile-lookup-by-link-or-id`) Actor

Resolve X post links or IDs into text, author, media, polls, quoted/parent posts, engagement metrics and replies, or resolve a handle into that account's public profile.

- **URL**: https://apify.com/vexaloom-labs/x-post-reply-and-profile-lookup-by-link-or-id.md
- **Developed by:** [vexaloom-labs](https://apify.com/vexaloom-labs) (community)
- **Categories:** Social media, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.49 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

## X Post, Reply & Profile Lookup by Link or ID

Give this actor a post link, a bare post ID, or a profile handle and it returns structured public data: the post's full text, author, media, poll, quoted and parent posts, engagement counts and replies — or that account's public profile. Optional quote collection turns a single post into the conversation around it. No login at any point.

### What this actor does

- **Posts by link or ID:** accepts `x.com` and `twitter.com` links, `x.com/i/web/status` links, bare post IDs, profile links and bare handles
- **Replies:** walks the replies X exposes to logged-out visitors, starting from the post's publication time, and de-duplicates them by reply ID
- **Quotes:** optionally collects the posts that quote the requested post, each with its text, author and metrics (off by default)
- **Retweeters:** optionally collects the handles of accounts that reposted the requested post (off by default; X exposes only a search-index sample of visible reposts)
- **Rich nested data:** optional parent post, quoted post, poll, link-preview card, photo/video variants and the author's public profile on every row
- **Profile input:** a profile link or handle returns one `profile` row with that account's public bio and counters
- **Honest rows:** every row carries a `type` (`post`, `reply`, `quote`, `profile`, `status`); deleted, protected or rate-limited links produce a `status` row with a message instead of failing the run
- **Empty fields are omitted** — the dataset never contains `null`, `""`, `[]` or `{}`

### Output per post or reply

Each row describes one post. `type` is `post` for requested posts and `reply` for replies collected from the conversation.

- `id` — post ID
- `url` — direct post URL
- `text` — full post text, multi-line and links intact
- `createdAt` — ISO 8601 post time
- `language` — post language code when X provides it
- `replyCount`, `retweetCount`, `likeCount`, `quoteCount`, `bookmarkCount`, `viewCount` — engagement metrics (views when X exposes them)
- `engagementRate` — derived `(likes + retweets + replies + quotes) / followers`; present only when the author's follower count is known and greater than zero
- `isReply`, `isQuote`, `isRetweet`, `isNoteTweet` — post type flags
- `conversationId` — the thread root of the post
- `threadRootId`, `threadPosition` — position of the row inside the collected thread
- `inReplyToTweetId`, `inReplyToUserId`, `inReplyToUsername` — where a reply points
- `hashtags`, `mentions`, `urls`, `cashtags` — entities found in the text
- `media` — photo/video/GIF objects
- `poll` — poll choices and status
- `card` — link-preview card (`title`, `description`, `domain`, `url`, `thumbnail`)
- `quotedTweet`, `quotedTweetId` — the quoted post when the input post quotes another (removed, together with `isQuote`, when `includeQuotedTweet` is off)
- `parentTweet` — the post being replied to when the input post is a reply
- `threadAncestors` — the chain of posts above a reply, root first (when `includeThreadAncestors` is on)
- `author` — author profile snapshot
- `authorProfile` — fuller author profile attached to every row
- `possiblySensitive`, `place`, `postedFrom` — extra labels when X exposes them
- `type`, `collectedAt`

**Media item:** `type` (`photo` / `video` / `gif`), `url`, `previewImageUrl`, `width`, `height`, `durationSeconds`, `viewCount`, `altText`, `variants` (each variant has `url`, `contentType`, `bitrate`).

**Poll:** `choices` (label + votes), `countsAreFinal`, `endsAt`, `durationMinutes`.

**Author:** `id`, `username`, `name`, `bio`, `bioLinks`, `bioEmails`, `website`, `location`, `followers`, `following`, `postCount`, `mediaCount`, `likesGiven`, `listedCount`, `isBlueVerified`, `verified`, `verifiedType`, `label`, `isProtected`, `profileImageUrl`, `bannerUrl`, `createdAt`. The last five counters are included when X publishes them for the account.

#### Sample record

```json
{
  "type": "post",
  "id": "1519480761749016577",
  "url": "https://x.com/i/status/1519480761749016577",
  "text": "Next I'm buying Coca-Cola to put the cocaine back in",
  "createdAt": "2022-04-28T00:56:58+00:00",
  "language": "en",
  "replyCount": 4056,
  "retweetCount": 4151,
  "likeCount": 91599,
  "quoteCount": 762,
  "viewCount": 246037082,
  "isReply": false,
  "isRetweet": false,
  "isQuote": false,
  "conversationId": "1519480761749016577",
  "threadRootId": "1519480761749016577",
  "threadPosition": 1,
  "author": { "username": "elonmusk", "name": "Elon Musk", "followers": 241741247 },
  "collectedAt": "2026-10-06T00:00:00+00:00"
}
```

### Output per quote row

When quote collection is on, each post that quotes the requested post is emitted as its own row with `type: "quote"` and the same fields as a post row. `quotedTweetId` points at the requested post, so quote rows are easy to separate from replies.

### Output per retweet row

When retweeter collection is on, each reposting account is emitted as a row with `type: "retweet"`. The row carries the retweeter's `id`, `url`, `createdAt` and `author` (with the public profile snapshot), and `retweetedTweetId` points at the post you requested. This list is an approximation: X only exposes a search-index sample of recent, visible reposts, so a post with many reposts can return far fewer handles than its repost count.

### Output per profile row

When you pass a profile link or handle instead of a post, the actor emits one `profile` row:

- `id`, `username`, `name`, `bio`, `bioLinks`, `bioEmails`, `location`, `website`
- `joinedAt`, `birthDate` — when public
- `followers`, `following`, `postCount`, `mediaCount`, `listedCount`, `likesGiven` — the last three when X publishes them
- `isBlueVerified`, `verified`, `verifiedType`, `isProtected`
- `avatarUrl`, `bannerUrl`
- `url` — profile URL
- `type: "profile"`, `collectedAt`

### Output per status row

A `status` row is emitted instead of data when a link cannot be collected. It always has a `message`:

- `type: "status"`
- `status` — `noInput`, `invalidLink`, `notFound`, `rateLimited` or `error`
- `tweetUrl` and `tweetId` (post inputs) or `profileUrl` (profile inputs)
- `collectedAt`

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `tweetUrls` | array | – | **Required.** Post links, `x.com/i/web/status` links, bare post IDs, or profile links/handles. `x.com` and `twitter.com` are both accepted. |
| `includeReplies` | boolean | `true` | Also collect the replies X exposes under each post. Turn off for the post only. |
| `maxReplies` | integer | `20` | Replies to collect per post (0–500). Very large threads can return fewer. |
| `includeQuotes` | boolean | `false` | Also collect the posts that quote each requested post, as `quote` rows. |
| `maxQuotes` | integer | `50` | Quote posts to collect per post (0–500). |
| `includeRetweeters` | boolean | `false` | Also collect handles of accounts that reposted each post, as `retweet` rows. Approximate: X exposes only a search-index sample of visible reposts. |
| `maxRetweeters` | integer | `50` | Retweeter handles to collect per post (0–500). |
| `includeQuotedTweet` | boolean | `true` | Include the quoted post's text, author and metrics. |
| `includeParentTweet` | boolean | `true` | When a collected post is a reply, attach the post it answers under `parentTweet`. |
| `includeThreadAncestors` | boolean | `false` | When a requested post is a reply, walk up to 10 posts back to the thread root and attach them under `threadAncestors`, root first. |
| `includeMedia` | boolean | `true` | Include image links, video links and video variants. |
| `includeAuthorProfile` | boolean | `true` | Attach the author's public profile details to every post, reply and quote row under `author` and `authorProfile`. |

#### Example: one post with its replies

```json
{
  "tweetUrls": ["https://x.com/NASA/status/2107095768821576019"],
  "includeReplies": true,
  "maxReplies": 100
}
```

#### Example: quotes and retweeters of a post

```json
{
  "tweetUrls": ["https://x.com/elonmusk/status/1519480761749016577"],
  "includeReplies": false,
  "includeQuotes": true,
  "maxQuotes": 100,
  "includeRetweeters": true,
  "maxRetweeters": 100
}
```

#### Example: quotes of a post, no replies

```json
{
  "tweetUrls": ["https://x.com/elonmusk/status/1519480761749016577"],
  "includeReplies": false,
  "includeQuotes": true,
  "maxQuotes": 100
}
```

#### Example: exact reply cap and no media

```json
{
  "tweetUrls": ["2106665276758491194"],
  "includeReplies": true,
  "maxReplies": 500,
  "includeMedia": false,
  "includeAuthorProfile": false
}
```

#### Example: mix posts, IDs and a profile

```json
{
  "tweetUrls": [
    "https://x.com/elonmusk/status/1519480761749016577",
    "2106665276758491194"
  ],
  "includeParentTweet": true
}
```

### Use cases

- **Brand and crisis monitoring** — collect a post, its replies and the posts quoting it to follow a conversation
- **Journalism and research** — archive exact text, timestamps, authors and metrics for citations
- **Social listening** — feed post, reply and quote text into sentiment or topic models
- **Customer support** — pull replies to your own posts for response triage
- **Dataset enrichment** — resolve a list of post IDs into structured records with author profiles
- **Compliance** — keep immutable evidence rows for posts you may need to reference later

### FAQ

**What data does this actor read?**  The same public post, profile and thread data any visitor sees on X without signing in. Nothing private is accessed.

**Do I need an X account, login or developer key?**  No. There is no login step and no credential input at all.

**Why do I get fewer replies than `maxReplies` or fewer than the post's reply counter?**  X only exposes part of a conversation to logged-out visitors, and some replies are deleted, protected or hidden. The actor collects everything public it can find, de-duplicated by reply ID, and never invents replies to fill the cap. Setting a larger cap and running again later can pick up more.

**Do quote rows include the post that was quoted?**  Yes. Each quote row is a normal post row, and its `quotedTweetId` points at the post you requested, so you can group quotes by target.

**Why are some profile counters missing?**  X does not publish every counter for every account on the logged-out profile view. The actor merges media, like and list counters from X's public profile widget when they are available; anything the source still omits stays absent rather than being filled with zero.

**Can I get the list of accounts that reposted or liked a post?**  Reposts: yes, approximately. With `includeRetweeters` the actor searches X for visible reposts of the post and returns their handles; X exposes only a recent search-index sample, so the list can be much shorter than the repost count. Likers: no — X does not publish who liked a post to logged-out visitors; the like count is returned instead.

**What happens with deleted, protected or hidden posts?**  You get a `status` row with `"status": "notFound"` and a message instead of data. The rest of the input is still processed.

**How fresh is the data?**  Live — every run reads X at request time. Schedule the actor for hourly or daily refreshes.

**Is this affiliated with X?**  No. This is a third-party actor that reads publicly available post and profile pages.

# Actor input Schema

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

Paste the posts you want to collect. You can also paste post IDs, x.com/i/web/status links, twitter.com links, profile links or bare handles (a profile input returns that profile's public details).

## `includeReplies` (type: `boolean`):

Collect the replies X shows for each post, walked forward from the post's publication time.

## `maxReplies` (type: `integer`):

How many replies to collect for each post (0-500). Posts with very large threads may return fewer because X does not expose every reply to logged-out visitors.

## `includeQuotes` (type: `boolean`):

Collect the posts that quote each requested post, with their text, author and engagement counts.

## `maxQuotes` (type: `integer`):

How many quote posts to collect for each requested post (0-500).

## `includeRetweeters` (type: `boolean`):

Collect the handles of accounts that reposted each requested post. X only exposes a search-index sample of visible reposts, so this is an approximate, recent-biased list.

## `maxRetweeters` (type: `integer`):

How many retweeter handles to collect for each post (0-500).

## `includeQuotedTweet` (type: `boolean`):

When a collected post quotes another post, attach the quoted post's text, author and metrics.

## `includeParentTweet` (type: `boolean`):

When a collected post is a reply, attach the post it answers under parentTweet.

## `includeThreadAncestors` (type: `boolean`):

When a requested post is a reply, walk up to 10 posts back to the start of the thread and attach them under threadAncestors (root first).

## `includeMedia` (type: `boolean`):

Include image links, video links and video variants for each post.

## `includeAuthorProfile` (type: `boolean`):

Attach the author's public profile details (followers, bio, verification) to every post, reply and quote row under author and authorProfile.

## Actor input object example

```json
{
  "tweetUrls": [
    "https://x.com/elonmusk/status/1519480761749016577",
    "2106665276758491194",
    "NASA"
  ],
  "includeReplies": true,
  "maxReplies": 3,
  "includeQuotes": false,
  "maxQuotes": 50,
  "includeRetweeters": false,
  "maxRetweeters": 50,
  "includeQuotedTweet": true,
  "includeParentTweet": true,
  "includeThreadAncestors": false,
  "includeMedia": true,
  "includeAuthorProfile": true
}
```

# Actor output Schema

## `tweets` (type: `string`):

All collected posts, replies and status rows.

# 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 = {
    "tweetUrls": [
        "https://x.com/NASA/status/2107095768821576019"
    ],
    "includeReplies": true,
    "maxReplies": 3,
    "includeQuotes": false,
    "includeRetweeters": false,
    "includeQuotedTweet": true,
    "includeParentTweet": true,
    "includeThreadAncestors": false,
    "includeMedia": true,
    "includeAuthorProfile": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("vexaloom-labs/x-post-reply-and-profile-lookup-by-link-or-id").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 = {
    "tweetUrls": ["https://x.com/NASA/status/2107095768821576019"],
    "includeReplies": True,
    "maxReplies": 3,
    "includeQuotes": False,
    "includeRetweeters": False,
    "includeQuotedTweet": True,
    "includeParentTweet": True,
    "includeThreadAncestors": False,
    "includeMedia": True,
    "includeAuthorProfile": True,
}

# Run the Actor and wait for it to finish
run = client.actor("vexaloom-labs/x-post-reply-and-profile-lookup-by-link-or-id").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 '{
  "tweetUrls": [
    "https://x.com/NASA/status/2107095768821576019"
  ],
  "includeReplies": true,
  "maxReplies": 3,
  "includeQuotes": false,
  "includeRetweeters": false,
  "includeQuotedTweet": true,
  "includeParentTweet": true,
  "includeThreadAncestors": false,
  "includeMedia": true,
  "includeAuthorProfile": true
}' |
apify call vexaloom-labs/x-post-reply-and-profile-lookup-by-link-or-id --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vexaloom-labs/x-post-reply-and-profile-lookup-by-link-or-id"
        }
    }
}
```

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/cMnafsv5dV5zfAsHX/builds/44rnh640txthNj7fH/openapi.json
