# X Profiles Scraper (`automation-lab/x-profile-scraper`) Actor

Extract public X profile metadata in bulk from handles or profile URLs for creator, brand, and audience enrichment.

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

## Pricing

Pay per event

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/platform/actors/running/actors-in-store#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

## X Profiles Scraper

Extract public **X profiles** in bulk from handles or profile URLs.
Get identity, biography, website, audience counts, verification flags, profile media, and account activity counts as structured JSON, CSV, or Excel-ready records.

The Actor is designed for recurring creator, brand, and audience enrichment.
It uses anonymously available X data and does not require your X login, cookies, or an X API key.

### What does X Profiles Scraper do?

Give the Actor a list such as `NASA`, `@NatGeo`, and `https://x.com/esa`.
It returns one normalized dataset row per public profile found.

Use it to:

- enrich creator and brand handle lists;
- prepare audience-research tables;
- refresh follower, following, post, and media counts;
- resolve current profile names, bios, websites, and locations;
- capture verification and protected-account flags;
- export profile records into spreadsheets, warehouses, or CRM workflows;
- schedule snapshots that your own workflow can compare over time.

The Actor focuses only on supplied-profile metadata.
It does not search for profiles, scrape posts, download followers, or calculate changes between runs.

### Who is this X profile extractor for?

#### Creator and influencer teams

Enrich a known list of creator handles before segmentation or outreach.
Use follower counts, profile links, bios, and verification flags as research signals, not as automatic quality scores.

#### Brand and competitive researchers

Refresh public identity and audience fields for known company accounts.
Run the same input on a schedule and compare exported snapshots downstream.

#### Data and RevOps teams

Turn mixed handles and URLs into consistently shaped records.
Connect the default dataset to Make, Zapier, webhooks, Google Sheets, or your warehouse.

#### Developers

Call the Actor through the Apify API and consume one stable record shape instead of maintaining guest-session and X response parsing code.

### Why use this Actor?

- **No X credentials:** no account, cookie, or private token input is requested.
- **Two input routes:** mix plain handles, `@handles`, x.com URLs, and twitter.com URLs.
- **Bulk-ready:** deduplicates handles case-insensitively and processes up to 1,000 supplied profiles per run.
- **Typed output:** profile identity, counts, links, booleans, media URLs, and timestamps have stable field names.
- **Cost-aware:** direct HTTP/API requests with no automatic browser or paid residential-proxy fallback.
- **Honest failures:** malformed inputs fail; unavailable profiles are logged and never emitted as fake empty records.

### What X profile data can you extract?

| Field | Meaning |
| --- | --- |
| `accountId` | Stable X account identifier |
| `username` | Current handle without `@` |
| `url` | Canonical x.com profile URL |
| `name` | Display name |
| `bio` | Public profile biography |
| `location` | Self-declared location |
| `website` | Expanded profile website, when present |
| `followersCount` | Public follower count |
| `followingCount` | Public following count |
| `postsCount` | Public post count reported by X |
| `likesCount` | Public likes count reported by X |
| `mediaCount` | Public media post count |
| `listedCount` | Number of public lists containing the profile |
| `isVerified` | Legacy or identity verification reported by X |
| `isBlueVerified` | Blue verification reported by X |
| `isProtected` | Whether posts are protected |
| `joinedAt` | Account creation date returned by X |
| `profileImageUrl` | Higher-resolution public profile image URL |
| `coverImageUrl` | Public profile banner URL, when present |
| `pinnedPostId` | Pinned post ID, when present |
| `scrapedAt` | Collection timestamp in ISO 8601 format |

Counts are snapshots from the source at collection time.
A null optional URL means X did not expose that field for the profile.

### How to scrape X profiles

1. Open the Actor input page.
2. Add handles under **X handles**, with or without `@`.
3. Optionally add x.com or twitter.com profile URLs under **X profile URLs**.
4. Set **Maximum profiles** to cap the unique profiles processed.
5. Click **Start**.
6. Open the **Dataset** tab when the run finishes.
7. Export results as JSON, CSV, Excel, XML, or RSS, or fetch them through the API.

Start with two or three known public organization accounts.
Then increase the input once the result shape fits your workflow.

### Input parameters

#### `usernames`

An array of X handles.
Accepted forms include:

```json
["NASA", "@NatGeo", "esa"]
```

Handles may contain letters, numbers, and underscores and are limited to X's 15-character handle format.
Duplicates such as `NASA` and `@nasa` produce one request.

#### `startUrls`

An Apify request-list field for explicit x.com or twitter.com profile URLs.
For example:

```json
[
  { "url": "https://x.com/NASA" },
  { "url": "https://twitter.com/esa" }
]
```

Other hosts and non-profile paths fail validation instead of being silently accepted.

#### `maxItems`

Maximum unique supplied profiles to process.
The default is `100`; the allowed range is `1` to `1000`.
This cap applies after handles and URLs are combined and deduplicated.

### Example input

```json
{
  "usernames": ["NASA", "NatGeo"],
  "startUrls": [
    { "url": "https://x.com/esa" }
  ],
  "maxItems": 3
}
```

### Example output

The exact counts and media URLs change over time.
A current result has this shape:

```json
{
  "accountId": "1234567890",
  "username": "samplebrand",
  "url": "https://x.com/samplebrand",
  "name": "Sample Brand",
  "bio": "Updates from a sample organization.",
  "location": "New York, NY",
  "website": "https://sample.org/",
  "followersCount": 125000,
  "followingCount": 250,
  "postsCount": 4200,
  "likesCount": 3500,
  "mediaCount": 1800,
  "listedCount": 320,
  "isVerified": false,
  "isBlueVerified": true,
  "isProtected": false,
  "joinedAt": "Mon Jan 15 12:00:00 +0000 2018",
  "profileImageUrl": "https://pbs.twimg.com/profile_images/1234567890/avatar_400x400.jpg",
  "coverImageUrl": "https://pbs.twimg.com/profile_banners/1234567890/1700000000",
  "pinnedPostId": "1800000000000000000",
  "scrapedAt": "2026-01-15T12:00:00.000Z"
}
```

This documentation uses anonymized values.
Live runs return current public source records.

### How much does it cost to extract X profiles?

The Actor uses pay-per-event pricing:

- **$0.005** once per run;
- one `X profile` event for each successfully saved dataset item;
- BRONZE price: **$0.006472 per saved profile**;
- lower per-profile tiers apply automatically at higher account usage tiers.

At the BRONZE tier:

| Saved profiles | BRONZE calculation |
| ---: | --- |
| 1 | one start event + 1 × profile event |
| 10 | one start event + 10 × profile event |
| 100 | one start event + 100 × profile event |
| 1,000 | one start event + 1,000 × profile event |

Unavailable, malformed, duplicate, or failed profiles do not create an item charge.
Apify platform usage can still apply according to your plan.
The live run input and Console estimate remain the final pricing authority.

### Recurring enrichment workflow

To monitor public profile metadata without inventing an unsupported built-in monitoring feature:

1. Save a Task containing the same handle list.
2. Add a daily or weekly Apify schedule.
3. Export each run's dataset to your destination.
4. Match rows by stable `accountId` rather than display name.
5. Compare `followersCount`, `bio`, `website`, and other fields in your database or automation.
6. Alert only after applying your own material-change thresholds.

Each run emits a fresh snapshot.
The Actor does not persist history or generate diffs itself.

### Export X profiles to a spreadsheet or pipeline

From the dataset, choose CSV or Excel for manual analysis.
For automated pipelines, request JSON from the default dataset API.

Useful patterns include:

- scheduled Task to Google Sheets through Make;
- webhook-triggered warehouse ingestion;
- CRM enrichment keyed by X account ID;
- creator-list refresh followed by your own scoring model;
- snapshot comparison in SQL or a notebook.

Do not use follower counts alone to infer authenticity, influence, identity, or eligibility.

### Run with the Apify API

Set `APIFY_TOKEN` in your environment.
Never place a real token in source code.

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~x-profile-scraper/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"usernames":["NASA","NatGeo"],"maxItems":2}'
```

To wait for output directly:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~x-profile-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"startUrls":[{"url":"https://x.com/NASA"}],"maxItems":1}'
```

#### JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/x-profile-scraper').call({
  usernames: ['NASA', 'NatGeo'],
  maxItems: 2,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/x-profile-scraper').call(run_input={
    'usernames': ['NASA', 'NatGeo'],
    'maxItems': 2,
})
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

### Use X Profiles Scraper with MCP

Add the Apify MCP server to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/x-profile-scraper"
```

#### Claude Desktop, Cursor, and VS Code setup

- **Claude Desktop:** add this object to the app's MCP server configuration.
- **Cursor:** add the same object under MCP settings.
- **VS Code:** add the same remote server configuration in your MCP-enabled extension.

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/x-profile-scraper"
    }
  }
}
```

Example prompts:

- “Run X Profiles Scraper for NASA, NatGeo, and esa, then summarize their public audience counts.”
- “Extract the public profile at https://x.com/NASA and return the website, bio, verification fields, and scrape timestamp.”
- “Enrich this approved list of brand handles and save the structured dataset for my pipeline.”

### Limits and data freshness

X can change its anonymous web interfaces, rate limits, and returned fields.
The Actor retries temporary network, 429, and server errors with bounded backoff.
It does not retry malformed input or stable unavailable-profile responses.

Protected profiles can still expose profile-level public metadata while their posts remain unavailable.
Suspended, deleted, withheld, or nonexistent profiles produce no row.
If every supplied profile is unavailable, the run fails rather than returning a misleading successful empty dataset.

This Actor does not scrape posts, follower lists, following lists, private content, emails, phone numbers, or historical snapshots.

### Troubleshooting

#### “Invalid X handle or profile URL”

Check that a handle is at most 15 characters and uses only letters, numbers, and underscores.
For URLs, use a direct `https://x.com/<handle>` or `https://twitter.com/<handle>` profile URL.

#### “No public X profiles were found”

Open the supplied profiles in a private browser window.
They may be misspelled, suspended, deleted, withheld, or unavailable anonymously.
Try one known public organization handle to distinguish input issues from an upstream incident.

#### Temporary X errors

Inspect run logs for HTTP status and retry messages.
Wait before retrying a large batch if X is rate-limiting anonymous traffic.
Split unrelated profile lists into separate Tasks only when that matches your business workflow; repeated retries can increase platform usage.

#### A field is empty or null

Optional profile fields are user-controlled and may not exist.
A blank location or null website is a valid source result, not necessarily a parser failure.

### Responsible and legal use

Use this Actor only for data you are authorized to collect and process.
Public visibility does not remove privacy, data-protection, contract, employment, marketing, or anti-discrimination obligations.

Follow X's terms, Apify's policies, and applicable laws.
Minimize retained personal data, document a lawful purpose, secure exports, honor deletion requirements, and avoid sensitive profiling.
Do not use output to make high-impact decisions without appropriate review and independent verification.

The Actor is an extraction tool, not legal advice and not a claim that every downstream use is permitted.

### Related Automation Lab Actors

- [X Follower Change Monitor](https://apify.com/automation-lab/x-follower-change-monitor) — maintain audience-count history and change records when that dedicated workflow is needed.
- [Twitter/X Lists Scraper](https://apify.com/automation-lab/twitter-lists-scraper) — extract curated list membership and related list data instead of only supplied profile metadata.

Choose this Actor when the primary unit is one supplied X profile.
Choose a related Actor when you need historical follower changes or list membership.

### FAQ

#### Does it require an X account or API key?

No.
The current supported route resolves anonymously public profile metadata without user-supplied X credentials.

#### Can it discover profiles from keywords?

No.
Supply handles or direct profile URLs.
The Actor intentionally does not claim search or discovery behavior.

#### Can it scrape tweets or followers?

No.
It returns profile metadata only.
Use a purpose-built posts, followers, or lists Actor for those different record types.

#### Can I schedule it?

Yes.
Save the input as an Apify Task and attach a schedule.
Each run produces a new snapshot; comparison and alerting are downstream responsibilities.

#### How are duplicates handled?

Handles and URL-derived handles are deduplicated case-insensitively before requests.
The first supplied spelling is used for the lookup.

#### Are missing profiles charged?

There is no per-item charge for an unavailable profile because no dataset row is saved.
The one-time run start event still applies.

#### Is the data real-time?

The result is a current source snapshot collected during the run, but no guarantee of real-time source synchronization is made.
Use `scrapedAt` to track when each record was collected.

# Actor input Schema

## `usernames` (type: `array`):

X handles with or without @. Duplicates are removed case-insensitively.

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

Public x.com or twitter.com profile URLs. You can combine these with handles.

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

Maximum number of unique supplied profiles to process in this run.

## Actor input object example

```json
{
  "usernames": [
    "NASA",
    "NatGeo"
  ],
  "startUrls": [],
  "maxItems": 3
}
```

# Actor output Schema

## `dataset` (type: `string`):

Public X profile records in the default 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 = {
    "usernames": [
        "NASA",
        "NatGeo"
    ],
    "maxItems": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/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 = {
    "usernames": [
        "NASA",
        "NatGeo",
    ],
    "maxItems": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/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 '{
  "usernames": [
    "NASA",
    "NatGeo"
  ],
  "maxItems": 3
}' |
apify call automation-lab/x-profile-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/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/inSDyVHJi8nCE3TkV/builds/BqyUhW5QenLf8kjWp/openapi.json
