# X (Twitter) Profile Scraper | $1.70/1K | 100 Posts Included (`feedminer/x-profile-scraper`) Actor

Scrape X (Twitter) profiles and their recent tweets from handles or URLs. Bio, followers, verification, links, plus tweet text, likes, retweets, replies and views. $1.70 per 1,000 profiles, first 100 posts of each included. By FeedMiner.

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

## Pricing

from $1.35 / 1,000 profile scrapeds

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>Turn any list of X (Twitter) handles into complete profile records.</strong> Bio, followers, verification, links, join date, plus their posts with likes, reposts, replies and views, as deep as X paginates. One handle in, one complete record out. No login, no API key, no code.
</div>

💸 **$1.70 per 1,000 profiles, with the first 100 posts of each included.** Only deep history bills beyond that.

🛡️ **Dead handles never kill a run.** Suspended, renamed and deleted accounts come back as rows marked `not_found` or `suspended` instead of failing the job.

⚡ **Built for speed.** A profile takes about a second, whether you ask for one or a thousand.

#### Copy to your AI assistant

```
feedminer/x-profile-scraper on Apify. Scrapes X (Twitter) profiles from handles or profile URLs. One row per profile with bio, follower and following counts, verification, join date and their posts nested in tweets[], as deep as X paginates, around 1,100 on a large account, each with likes, reposts, replies, quotes, bookmarks and views. Call ApifyClient("TOKEN").actor("feedminer/x-profile-scraper").call(run_input={...}), then client.dataset(run["defaultDatasetId"]).list_items().items. Requires handles (string[]); includeTweets (bool), maxTweetsPerProfile (int, first 100 included in the profile price) and onlyPostsNewerThan (YYYY-MM-DD) control the posts. Full spec: GET https://api.apify.com/v2/acts/feedminer~x-profile-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-LtjypQU3luntehtJW-FJdKJEBFYb-IMG_9471.jpeg" width="26" height="26" style="vertical-align:-4px;border-radius:6px"/> How to scrape X (Twitter) profiles

Paste handles or profile URLs, press Start. `jack`, `@jack` and `https://x.com/jack` all work, mixed lists too, duplicates removed for you.

##### Basic: check one account

```json
{ "handles": ["nasa"], "includeTweets": false }
```

Profile only, no posts. The cheapest and fastest way to get follower counts.

##### Enrich a prospect list

```json
{ "handles": ["stripe", "vercel", "supabase", "linear"], "includeTweets": false }
```

Drop a column of handles from your CRM in, get bios, links and audience sizes back.

##### Benchmark competitors on a month of posts

```json
{
  "handles": ["openai", "anthropicai", "googledeepmind"],
  "maxTweetsPerProfile": 3200,
  "onlyPostsNewerThan": "2026-06-01",
  "excludeRetweets": true
}
```

The run stops at your date instead of walking the whole timeline, so it stays fast and cheap.

##### Full history of one account

```json
{ "handles": ["nasa"], "maxTweetsPerProfile": 3200 }
```

As deep as X paginates, newest first, in one dataset. Measured on a large account: around 1,100 posts. X's documented ceiling for any tool, its own API included, is 3,200.

***

### Input parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| `handles` | array | required | Handles or profile URLs, any format, mixed |
| `includeTweets` | boolean | `true` | Also scrape posts. Off is faster and ideal for pure audience data |
| `maxTweetsPerProfile` | integer | `20` | Posts per profile, newest first. Ask for 3,200 and the run goes as deep as X paginates |
| `onlyPostsNewerThan` | string | | Stop at this date, for example `2026-01-31` |
| `excludeRetweets` | boolean | `false` | Keep only what the account actually wrote |
| `debugMode` | boolean | `false` | Extra logging for troubleshooting |

***

### What data can you extract from an X (Twitter) profile?

| Field | Type | Description |
|---|---|---|
| `handle`, `name`, `userId` | string | Handle, display name, and the stable numeric ID that survives renames |
| `bio`, `location`, `website` | string | Profile content, website unwrapped to its real destination |
| `followers`, `following` | integer | Audience counts |
| `tweetsCount`, `likesCount`, `listedCount`, `mediaCount` | integer | Activity counts |
| `verified`, `blueVerified`, `protected` | boolean | Badges and privacy |
| `accountType` | string | `personal`, `business`, or the creator category |
| `profileImage`, `bannerImage` | string | Avatar at full resolution, header image |
| `createdAt` | string | Join date, ISO format |
| `pinnedTweetIds` | array | What the account chose to pin |
| `status` | string | `ok`, `not_found`, `suspended`, or `error` |
| `tweets` | array | The posts, nested inside their author |

Each nested post carries: text, date, likes, retweets, replies, quotes, bookmarks, views, media with playable MP4 links, hashtags, mentions, unwrapped links, language, and type flags (`isRetweet`, `isReply`, `isQuote`, `isPinned`).

##### Example row

```json
{
  "handle": "openai",
  "name": "OpenAI",
  "userId": "4398626122",
  "url": "https://x.com/openai",
  "bio": "OpenAI's mission is to ensure that artificial general intelligence benefits all of humanity.",
  "website": "https://openai.com",
  "followers": 5030803,
  "following": 4,
  "tweetsCount": 1994,
  "listedCount": 39051,
  "verified": false,
  "blueVerified": true,
  "accountType": "business",
  "createdAt": "2015-12-06T22:51:08Z",
  "pinnedTweetIds": ["2077446718728425686"],
  "status": "ok",
  "tweets": [
    {
      "id": "2077446718728425686",
      "url": "https://x.com/openai/status/2077446718728425686",
      "text": "Introducing GPT-Red\n\nAn internal automated red teamer on a mission to break our own models.",
      "createdAt": "2026-07-15T17:34:29Z",
      "likes": 7959,
      "retweets": 751,
      "replies": 402,
      "quotes": 118,
      "bookmarks": 1204,
      "views": 1437188,
      "isPinned": true,
      "authorHandle": "openai"
    }
  ]
}
```

***

### Pricing: Pay Per Event (PPE)

| Event | Price | Per 1,000 |
|---|---|---|
| Profile scraped, first 100 posts included | $0.0017 | $1.70 |
| Each post beyond those 100 | $0.00012 | $0.12 |
| Run start | $0.002 | |

A run with the default 20 posts per profile only ever pays the profile price plus the start. Only deep history runs touch the per-post line. The profile and post prices step down on their own for the larger Apify plans, to $1.50 and then $1.35 per 1,000 profiles.

| Run | Cost |
|---|---|
| Vet an influencer on their last 100 posts | under half a cent |
| Benchmark 4 competitors on a month of posts | about 3 cents |
| One account's whole available timeline, around 1,100 posts | $0.13 |
| A daily 10 account monitor, for a whole month | $0.57 |
| Enrich 1,000 handles with audience data | $1.70 |

For comparison, the market leader charges $16 per 1,000 profiles with 40 posts included, then $0.40 per 1,000 posts beyond. The same profile costs 9 times less here and brings 2.5 times more posts with it.

##### Free tier

The Apify free plan includes $5 of usage every month, which is almost 3,000 profiles here. No card required.

***

### Advanced usage

##### Track follower growth over time

Schedule a daily run with `includeTweets` off and append the dataset to a sheet. Each run stamps `scrapedAt`, so a simple line chart gives follower growth per competitor with no extra tooling.

##### Stop at a date instead of paying for history you throw away

Set `onlyPostsNewerThan` and the run stops there rather than pulling everything and filtering afterwards. Cheaper and faster.

##### Keep engagement averages honest

Some accounts are more than half reposts. `excludeRetweets: true` keeps only what the account wrote. And when you do keep reposts, filter on `isRetweet` before averaging: a repost's likes live on the original, so the repost row shows 0.

##### Use the right join key

`userId`, not `handle`. People rename their accounts and the handle follows them; the numeric ID never changes.

##### Built to survive X changes

X reshapes its site constantly, which is why so many X scrapers go dark for days. This one is built to absorb those changes without a pause, so a run keeps returning profiles instead of an empty dataset.

***

### Integrate profiles into your stack

Results flow through the Apify API into Python, JavaScript, Google Sheets, Make, Zapier, n8n or Slack. Runs can be scheduled daily, monitored and chained with other Actors.

##### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

run = client.actor("feedminer/x-profile-scraper").call(run_input={
    "handles": ["jack", "openai", "nasa"],
    "includeTweets": True,
    "maxTweetsPerProfile": 50,
})

for profile in client.dataset(run["defaultDatasetId"]).iterate_items():
    tweets = profile.get("tweets", [])
    avg_views = sum(t["views"] for t in tweets) / len(tweets) if tweets else 0
    print(f"@{profile['handle']:15} {profile['followers']:>10,} followers {avg_views:>10,.0f} avg views")
```

##### JavaScript

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

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });

const run = await client.actor('feedminer/x-profile-scraper').call({
    handles: ['jack', 'https://x.com/openai'],
    maxTweetsPerProfile: 20,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const profile of items) {
    const best = (profile.tweets ?? []).sort((a, b) => b.views - a.views)[0];
    if (best) console.log(`@${profile.handle}: ${best.views.toLocaleString()} views`);
}
```

***

### Performance

| Measure | Value |
|---|---|
| Speed | About one second per profile |
| Posts per profile | As deep as X paginates, around 1,100 measured on a large account. X's own ceiling is 3,200 |
| Dead handles | Returned as rows marked not\_found or suspended, the run keeps going |
| Partial results | Kept and delivered when a limit is reached, never discarded |

***

### FAQ

**Do I need an X account, a login, or an API key?**
No. Paste handles and press Start. You never connect an account of your own.

**How many posts can I get per profile?**
Up to 3,200, as deep as X lets anyone go on a timeline, including the official API. The default is 20 to keep quick runs cheap, and the first 100 are included in the profile price.

**Can I get follower lists or the replies an account wrote?**
Not with this Actor: it works from handles and returns profiles with their posts. You get every count, and posts that are replies are flagged `isReply`.

**What happens with private, suspended or deleted accounts?**
They come back as rows with a `status` of `suspended` or `not_found`, and the run finishes normally. Private accounts return their public profile without posts.

**Does it work for accounts in other languages?**
Yes. Bios and posts come back in the original language and script, emoji intact, with a detected `lang` on each post.

**Are view counts included?**
Yes, on every post that has them. Posts from before X published view counts return 0.

**Can I search X by keyword with this Actor?**
Not with this one, it works from handles and URLs you already have. Keyword search is what the [FeedMiner Tweet Scraper](https://apify.com/feedminer/x-tweet-scraper) does.

***

### Support

- Found an account that does not scrape correctly, or need a field that is missing? Open the **Issues** tab on this Actor's page with the handle and the field. Issues are read daily.
- Need a custom variant of this scraper for your pipeline? Ask in the Issues tab, FeedMiner builds on request.

### Legal compliance

This scraper collects only public data, the same information any visitor sees on x.com without logging in. Profiles can contain personal data: processing information about people in the EU, the UK or California requires a lawful basis under GDPR or CCPA, and deletion and access requests must be honoured. Use the data for research, analytics and business intelligence, not for spam lists or harassment.

***

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

[X Tweet Scraper](https://apify.com/feedminer/x-tweet-scraper) · X Profile Scraper · [All FeedMiner Actors](https://apify.com/feedminer)

# Actor input Schema

## `handles` (type: `array`):

Handles or profile URLs to scrape. Accepts jack, @jack, or https://x.com/jack

## `includeTweets` (type: `boolean`):

Also scrape each profile's recent tweets. Turn off for profile data only, which is faster and cheaper.

## `maxTweetsPerProfile` (type: `integer`):

Maximum number of tweets to scrape per profile, newest first. X exposes up to 3200 per profile. Higher numbers take longer.

## `onlyPostsNewerThan` (type: `string`):

Stop at this date, for example 2026-01-31. Leave empty to scrape the newest posts up to your limit.

## `excludeRetweets` (type: `boolean`):

Skip reposts of other accounts and keep only the account's own posts.

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

Log extra detail for troubleshooting.

## Actor input object example

```json
{
  "handles": [
    "nasa"
  ],
  "includeTweets": true,
  "maxTweetsPerProfile": 20,
  "onlyPostsNewerThan": "2026-01-01",
  "excludeRetweets": false,
  "debugMode": false
}
```

# Actor output Schema

## `profiles` (type: `string`):

All scraped profiles with bio, followers, following, tweet counts, verification, links and their recent tweets.

# 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 = {
    "handles": [
        "jack",
        "https://x.com/OpenAI"
    ],
    "maxTweetsPerProfile": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("feedminer/x-profile-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 = {
    "handles": [
        "jack",
        "https://x.com/OpenAI",
    ],
    "maxTweetsPerProfile": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("feedminer/x-profile-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 '{
  "handles": [
    "jack",
    "https://x.com/OpenAI"
  ],
  "maxTweetsPerProfile": 20
}' |
apify call feedminer/x-profile-scraper --silent --output-dataset

```

## MCP server setup

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