# X (Twitter) Profile & Post Scraper (`barefoot_grade/x-twitter-scraper`) Actor

Collect public X (Twitter) profiles and posts by link. Profiles come with exact follower, following and post counts, bio, website, verification and join date, plus latest posts. Posts come with text, media and exact likes, reposts, replies, quotes, bookmarks and views. Pay only for rows delivered.

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

## Pricing

from $0.20 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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 (Twitter) Profile & Post Scraper

Turn X (Twitter) usernames, profile links and post links into clean, structured rows. Every profile comes with its **exact follower, following and post counts**, bio, location, website, verification type, join date, avatar and banner, plus its latest posts. Every post comes with its text, author, posting time, photos and videos, and **exact likes, reposts, replies, quotes, bookmarks and views**. No X account or login is needed.

Paste as many profiles and posts as you like in one run. Profiles bring their latest posts (up to 5, pinned post included), and post links bring the top replies X shows under them. A total row cap keeps big lists from running away. Profiles and posts that cannot be read are listed in the run summary and are not charged.

### What it covers

- **Profiles** by username or link: the profile itself and the latest posts X shows on it to visitors (up to 5).
- **Posts** by link or id: the post with every public counter, plus the top replies X shows under it (usually 2 to 5).
- **Not covered**: X search, hashtag pages, a profile's full post history beyond its latest posts, the replies tab, likes, and follower or following lists. X shows these only to signed-in visitors, so links to them are rejected with a clear message.

### Use cases

- **Influencer and creator vetting**: exact follower counts, verification type, join date and how well the latest posts perform.
- **Brand and competitor tracking**: re-run the same accounts on a schedule and compare followers and engagement over time.
- **Campaign reporting**: likes, reposts, replies, quotes, bookmarks and views for a list of post links in one table.
- **Lead and account enrichment**: bio, location and website for a list of X handles.
- **Research and AI datasets**: post text, media and top replies as clean rows.

### Quick Start

```json
{
  "startUrls": ["NASA", "https://x.com/jack/status/20"],
  "maxItems": 100
}
```

The first line gives NASA's profile and its latest posts; the second gives the post and its top replies.

### Input

| Input | Type | Default | Meaning |
| --- | --- | --- | --- |
| `startUrls` | array | — | One per line: a username (`NASA` or `@NASA`), a profile link (`https://x.com/NASA`), a post link (`https://x.com/NASA/status/2112553116390269175`) or a post id. `twitter.com` links work too. |
| `includeLatestPosts` | boolean | `true` | Also collect the latest posts each profile shows to visitors, with their exact counts. |
| `maxPostsPerProfile` | integer | `5` | How many of each profile's latest posts to keep, 1 to 5. |
| `includeReplies` | boolean | `true` | Also collect the top replies X shows under each post link. Each reply is one row. |
| `maxItems` | integer | `1000` | Total cap on rows (profiles plus posts) across every input line, up to 100,000. |

Give at least one username, profile link or post link.

### Example queries

- `{"startUrls": ["NASA", "SpaceX", "ESA"], "includeLatestPosts": false}`: three profiles, one row each.
- `{"startUrls": ["https://x.com/nike", "https://x.com/adidas", "https://x.com/PUMA"], "maxPostsPerProfile": 3}`: competitor profiles with their 3 latest posts.
- `{"startUrls": ["https://x.com/NASA/status/2112553116390269175", "https://x.com/jack/status/20"], "includeReplies": false}`: counters for a list of posts.
- `{"startUrls": ["2112553116390269175"]}`: a post by its id, with its top replies.
- `{"startUrls": ["@BarackObama", "@taylorswift13", "@elonmusk"], "maxItems": 50}`

### What it returns

The dataset has one row per profile and one row per post. The `type` field tells them apart, and `origin` says why a row is there: `requested` (from your input), `latest` (a profile's latest post) or `reply` (a top reply under a post link).

Profiles (`"type": "profile"`):

| Field | Meaning |
| --- | --- |
| `id` | X's numeric account id. |
| `username`, `name` | Handle without `@`, and display name. |
| `url` | The profile on X. |
| `bio`, `location`, `website` | As shown on the profile, with links expanded. |
| `createdAt` | Join date (UTC, ISO 8601). |
| `followers`, `following`, `postsCount` | Exact counts. |
| `isBlueVerified`, `verifiedType` | Blue check, and `Business` or `Government` for organisation badges. |
| `isProtected` | `true` for protected accounts (their posts are hidden). |
| `avatarUrl`, `bannerUrl` | Profile picture (400 x 400) and header image. |
| `professionalType`, `affiliatesCount`, `subscribersCount` | Creator or business label, affiliated accounts and subscribers, when shown. |
| `latestPostIds` | Ids of the latest posts delivered for this profile. |

Posts (`"type": "post"`):

| Field | Meaning |
| --- | --- |
| `id`, `url` | X's post id and the post link. |
| `text` | Full post text (long posts included) with links expanded. |
| `lang`, `createdAt` | Language code and posting time (UTC, ISO 8601). |
| `authorId`, `authorUsername`, `authorName`, `authorFollowers`, `authorIsBlueVerified`, `authorVerifiedType`, `authorAvatarUrl` | Who posted it. |
| `likes`, `reposts`, `replies`, `quotes`, `bookmarks` | Exact counts. |
| `views` | Exact view count; `null` for older posts that X shows without one. |
| `media` | Photos, videos and GIFs: `type`, `url`, `width`, `height`, `altText`, and for videos `videoUrl` (best quality MP4) and `durationMs`. |
| `hashtags`, `mentions`, `links` | Hashtags, mentioned usernames and expanded links. |
| `isReply`, `inReplyToId`, `inReplyToUsername` | Reply details. |
| `isQuote`, `quotedPost` | The quoted post with its text, author and counts. |
| `isPinned` | `true` for a profile's pinned post. |
| `possiblySensitive` | X's sensitive-content flag. |
| `countsPartial` | `true` on the rare post where X showed only its likes and reply count (the other counters are `null`). |

Every row also has `source` (the input line it came from) and `scrapedAt` (collection time, UTC).

The run summary (`OUTPUT`) reports `profiles`, `posts`, `replies`, and any profile or post that could not be read in `sourceErrors`, each with a short code and message (for example `NOT_FOUND` for a misspelled handle or a deleted post, `SUSPENDED`, or `UNAVAILABLE`). A post that appears twice (say as a profile's latest post and as a post link) is delivered and charged once.

### Output example

```jsonl
{"type": "profile", "id": "11348282", "username": "NASA", "name": "NASA", "url": "https://x.com/NASA", "bio": "Making the seemingly impossible, possible. ✨", "location": "Pale Blue Dot", "website": "http://www.nasa.gov/", "createdAt": "2007-12-19T20:20:32Z", "followers": 92317762, "following": 115, "postsCount": 74443, "isBlueVerified": true, "verifiedType": "Government", "isProtected": false, "avatarUrl": "https://pbs.twimg.com/profile_images/1321163587679784960/0ZxKlEKB_400x400.jpg", "bannerUrl": "https://pbs.twimg.com/profile_banners/11348282/1788992290", "professionalType": null, "affiliatesCount": 85, "subscribersCount": 0, "latestPostIds": ["2112604875452223824"], "origin": "requested", "source": "NASA", "scrapedAt": "2026-10-20T18:40:12.345Z"}
{"type": "post", "id": "2112604875452223824", "url": "https://x.com/NASA/status/2112604875452223824", "text": "LIVE: Get a preview of two upcoming spacewalks set for Oct. 29 and Nov. 5. @astro_anil and CSA (Canadian Space Agency) astronaut Joshua Kutryk will use both spacewalks to finish installing solar arrays. https://x.com/i/broadcasts/1jxXgBNWypPJZ", "lang": "en", "createdAt": "2026-10-20T18:00:27Z", "authorId": "11348282", "authorUsername": "NASA", "authorName": "NASA", "authorFollowers": 92317762, "authorIsBlueVerified": true, "authorVerifiedType": "Government", "authorAvatarUrl": "https://pbs.twimg.com/profile_images/1321163587679784960/0ZxKlEKB_400x400.jpg", "likes": 151, "reposts": 25, "replies": 13, "quotes": 0, "bookmarks": 5, "views": 78493, "media": [], "hashtags": [], "mentions": ["astro_anil"], "links": ["https://x.com/i/broadcasts/1jxXgBNWypPJZ"], "possiblySensitive": false, "isReply": false, "inReplyToId": null, "inReplyToUsername": null, "isQuote": false, "quotedPost": null, "isPinned": false, "origin": "latest", "source": "NASA", "scrapedAt": "2026-10-20T18:40:12.345Z"}
{"type": "post", "id": "20", "url": "https://x.com/jack/status/20", "text": "just setting up my twttr", "lang": "en", "createdAt": "2006-03-21T20:50:14Z", "authorId": "12", "authorUsername": "jack", "authorName": "jack", "authorFollowers": 12533196, "authorIsBlueVerified": true, "authorVerifiedType": null, "authorAvatarUrl": "https://pbs.twimg.com/profile_images/1661201415899951105/azNjKOSH_400x400.jpg", "likes": 309156, "reposts": 124596, "replies": 18107, "quotes": 7325, "bookmarks": 21982, "views": null, "media": [], "hashtags": [], "mentions": [], "links": [], "possiblySensitive": null, "isReply": false, "inReplyToId": null, "inReplyToUsername": null, "isQuote": false, "quotedPost": null, "origin": "requested", "source": "https://x.com/jack/status/20", "scrapedAt": "2026-10-20T18:40:12.345Z"}
{"type": "post", "id": "1770888775830262034", "url": "https://x.com/derbederdusler/status/1770888775830262034", "text": "@jack", "lang": "qme", "createdAt": "2024-03-21T19:02:40Z", "authorId": "1420469290369789958", "authorUsername": "derbederdusler", "authorName": "𝕯𝖊𝖗𝖇𝖊𝖉𝖊𝖗", "authorFollowers": 3922, "authorIsBlueVerified": true, "authorVerifiedType": null, "authorAvatarUrl": "https://pbs.twimg.com/profile_images/2068802435938689025/Iqb-7nQc_400x400.jpg", "likes": 8012, "reposts": 139, "replies": 22, "quotes": 7, "bookmarks": 95, "views": 462713, "media": [{"type": "photo", "url": "https://pbs.twimg.com/media/GJN19MHXQAAeNDq.jpg", "width": 1080, "height": 786}], "hashtags": [], "mentions": ["jack"], "links": [], "possiblySensitive": false, "isReply": true, "inReplyToId": "20", "inReplyToUsername": "jack", "isQuote": false, "quotedPost": null, "origin": "reply", "source": "https://x.com/jack/status/20", "scrapedAt": "2026-10-20T18:40:12.345Z"}
```

### How fast

About **250 profiles or post links a minute**. A profile with its 5 latest posts is 6 rows, so a list of 100 profiles gives about 600 rows in under a minute.

### Price

**$0.0002 per row** delivered (one profile or one post), that is $0.20 per 1,000 rows, plus **$0.005 per run start**. The run-start event is charged per GB of memory; the default 512 MB run is one start event. The start is charged even if the run saves no results. Profiles and posts that could not be read are not charged. Platform usage is included in these prices.

### Good to know

- Counts are a snapshot at collection time.
- A profile shows visitors only its latest posts (up to 5, including a pinned post). For more posts from one account, add their post links.
- Reposts made by a profile are not part of its latest posts; its own posts and quote posts are.
- Protected accounts give their profile row; their posts are hidden. Suspended accounts and deleted posts are reported in `OUTPUT.sourceErrors` and are not charged.
- Older posts (before X started counting views) have `views: null`.
- If X temporarily refuses requests, the run retries with growing pauses. Rows already collected are kept. If nothing at all can be read, the run fails with a clear message.

# Actor input Schema

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

One per line: a username (NASA or @NASA), a profile link (https://x.com/NASA), a post link (https://x.com/NASA/status/...) or a post id. twitter.com links work too.

## `includeLatestPosts` (type: `boolean`):

Also collect the latest posts each profile shows to visitors (up to 5, including a pinned post), each with exact likes, reposts, replies, quotes, bookmarks and views.

## `maxPostsPerProfile` (type: `integer`):

How many of a profile's latest posts to keep, 1 to 5.

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

Also collect the top replies X shows under each post link (usually 2 to 5). Each reply is one row.

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

Total cap on profiles plus posts across every input line. The run stops when it is reached.

## Actor input object example

```json
{
  "startUrls": [
    "NASA",
    "https://x.com/jack/status/20"
  ],
  "includeLatestPosts": true,
  "maxPostsPerProfile": 5,
  "includeReplies": true,
  "maxItems": 100
}
```

# Actor output Schema

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

No description

## `summary` (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": [
        "NASA",
        "https://x.com/jack/status/20"
    ],
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("barefoot_grade/x-twitter-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": [
        "NASA",
        "https://x.com/jack/status/20",
    ],
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("barefoot_grade/x-twitter-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": [
    "NASA",
    "https://x.com/jack/status/20"
  ],
  "maxItems": 100
}' |
apify call barefoot_grade/x-twitter-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,barefoot_grade/x-twitter-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/RazWFyyHC1siJxxZl/builds/W1Q0htGp1dGBNaMyr/openapi.json
