# Twitter/X Profile Scraper · Bulk Handles, URLs & IDs (`data-slayer/twitter-user`) Actor

Extract public Twitter/X profile data from handles, profile URLs, or numeric user IDs. Export bios, follower and following counts, verification, images, location, account dates, and stable IDs to JSON, CSV, or Excel.

- **URL**: https://apify.com/data-slayer/twitter-user.md
- **Developed by:** [Data Slayer](https://apify.com/data-slayer) (community)
- **Categories:** Social media, Lead generation, Other
- **Features:** Limited permissions
- **Stats:** 261 total users, 29 monthly users, 84.6% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 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.
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 Profile Scraper · Bulk Handles, URLs & IDs

Turn Twitter/X handles, profile URLs, or stable numeric user IDs into structured public profile rows for CRM enrichment, creator research, audience analysis, and recurring profile monitoring.

### Watch the demo

[![Watch the Twitter/X Profile Scraper demo](https://img.youtube.com/vi/nzBwmRl1Bk0/hqdefault.jpg)](https://www.youtube.com/watch?v=nzBwmRl1Bk0)

### What this Actor does

Submit one profile or a batch of up to 100 references. The Actor normalizes handles and URLs, removes duplicate inputs, retries temporary retrieval failures within strict limits, and writes one successful profile per stable user ID to the default dataset.

Successful profiles are the only default-dataset rows. Invalid, missing, unavailable, partial, and cancelled outcomes are recorded in the run's `RUN_SUMMARY` key-value record, so diagnostic status records do not become paid dataset results.

### Input

The simplest batch input is `profiles`:

```json
{
  "profiles": [
    "nasa",
    "@apify",
    "https://x.com/openai",
    "11348282"
  ],
  "maxItems": 100
}
```

| Field | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `profiles` | array of strings | Conditional | — | Handles, `@handles`, `x.com`/`twitter.com` profile URLs, or numeric user IDs. |
| `maxItems` | integer | No | `100` | Maximum unique references to process; range `1`–`100`. |
| `username` | string | Conditional | — | Backward-compatible single-username input. Existing API integrations can keep using it. |
| `usernames` | array of strings | No | — | Compatibility alias for batch handles. |
| `profileUrls` | array of strings | No | — | Compatibility alias for batch profile URLs. |
| `userIds` | array of strings | No | — | Compatibility alias for numeric user IDs. |

Provide at least one reference through `username` or a list field. When the same profile is submitted more than once, the first occurrence determines its `requested_input`; later duplicates are skipped.

### Output

The default dataset preserves the established fields used by existing customers and adds stable, documented aliases for new integrations.

#### Canonical fields

| Field | Type | Nullable | Description |
| --- | --- | --- | --- |
| `record_type` | string | No | Always `profile`. |
| `requested_input` | string | No | The first input reference that produced this row. |
| `input_type` | string | No | `handle` or `user_id`. |
| `user_id` | string | Yes | Stable numeric user ID when available. |
| `username` | string | Yes | Current account handle. |
| `display_name` | string | Yes | Public display name. |
| `bio` | string | Yes | Public profile biography. |
| `followers_count` | integer | Yes | Public follower count at collection time. |
| `following_count` | integer | Yes | Public following count at collection time. |
| `posts_count` | integer | Yes | Public post count at collection time. |
| `is_blue_verified` | boolean | Yes | Blue verification state when available. |
| `is_protected` | boolean | Yes | Whether posts are protected. Public profile-header fields may still be available. |
| `profile_image_url` | string | Yes | Public profile image URL. |
| `banner_image_url` | string | Yes | Public banner image URL. |
| `profile_url` | string | Yes | Canonical `x.com` profile URL when a handle is available. |
| `collected_at` | ISO 8601 string | No | Time this Actor mapped the profile row. |

#### Preserved legacy fields

Existing fields remain available when returned: `id`, `profile`, `rest_id`, `blue_verified`, `affiliates`, `avatar`, `header_image`, `desc`, `name`, `location`, `friends`, `sub_count`, `statuses_count`, `media_count`, `created_at`, `pinned_tweet_ids_str`, `protected`, `status`, `website`, `verified`, `can_dm`, `fast_followers_count`, `favourites_count`, `listed_count`, `normal_followers_count`, and `possibly_sensitive`.

#### Example JSON result

```json
{
  "status": "active",
  "profile": "NASA",
  "rest_id": "11348282",
  "blue_verified": true,
  "avatar": "https://pbs.twimg.com/profile_images/example.jpg",
  "header_image": "https://pbs.twimg.com/profile_banners/11348282/example",
  "desc": "Exploring Earth and the universe.",
  "name": "NASA",
  "location": "Pale Blue Dot",
  "friends": 117,
  "sub_count": 92385617,
  "statuses_count": 74276,
  "media_count": 27942,
  "protected": false,
  "user_id": "11348282",
  "username": "NASA",
  "display_name": "NASA",
  "bio": "Exploring Earth and the universe.",
  "followers_count": 92385617,
  "following_count": 117,
  "posts_count": 74276,
  "is_blue_verified": true,
  "is_protected": false,
  "requested_input": "nasa",
  "input_type": "handle",
  "profile_url": "https://x.com/NASA",
  "collected_at": "2026-09-21T00:00:00+00:00",
  "record_type": "profile"
}
```

#### Example CSV

```csv
requested_input,user_id,username,display_name,followers_count,following_count,posts_count,is_blue_verified,is_protected,profile_url,collected_at
nasa,11348282,NASA,NASA,92385617,117,74276,true,false,https://x.com/NASA,2026-09-21T00:00:00+00:00
```

### Empty, unavailable, and partial results

Open `RUN_SUMMARY` in the default key-value store to reconcile every accepted input.

- `succeeded`: a profile row was written.
- `empty`: no profile was returned; no diagnostic dataset row was created.
- `failed`: retrieval or validation failed with a stable functional code.
- `partial`: at least one profile was written, but a safe cursor or budget boundary stopped additional work.
- `cancelled`: the run stopped before all accepted inputs were processed.

Errors use functional codes such as `PROFILE_NOT_FOUND`, `DATA_ACCESS_UNAVAILABLE`, `RATE_LIMITED`, `DATA_TEMPORARILY_UNAVAILABLE`, `MALFORMED_RESPONSE`, and `REQUEST_BUDGET_EXCEEDED`. Raw response bodies, private request URLs, credentials, and internal exception text are not included in customer output or logs.

### Pricing

The proposed pricing remains pay per successful default-dataset profile plus the existing small Actor-start event. A missing or failed profile creates no default-dataset item.

| Apify plan | Price per profile | Price per 1,000 profiles |
| --- | ---: | ---: |
| Free | $0.00250 | $2.50 |
| Bronze | $0.00217 | $2.17 |
| Silver | $0.00183 | $1.83 |
| Gold | $0.00150 | $1.50 |
| Platinum | $0.00150 | $1.50 |
| Diamond | $0.00150 | $1.50 |

The Actor-start event is $0.002 per run, with the platform's existing memory-based event semantics and a minimum of one start event.

### How to run it

1. Add handles, profile URLs, or numeric IDs to **Profile handles, URLs, or IDs**.
2. Keep `maxItems` at 100 or lower it for a smaller test.
3. Start the Actor.
4. Download successful rows as JSON, CSV, Excel, XML, or HTML from the dataset.
5. Check `RUN_SUMMARY` for empty, invalid, unavailable, partial, or cancelled inputs.

For an existing integration, this input remains valid:

```json
{
  "username": "nasa"
}
```

### Automation and API use

Use the Actor from the Apify API, schedules, tasks, webhooks, Make, Zapier, n8n, or another workflow tool. Store `user_id` as the durable join key where available; handles can change.

### Common use cases

- Enrich CRM records with public profile identity and audience-size fields.
- Qualify creators and partners by public account metadata.
- Refresh a known profile list on a schedule and compare snapshots in your own warehouse.
- Resolve mixed handle/URL columns without preprocessing them first.
- Build research datasets while retaining the submitted input for traceability.

### Limits and responsible use

- Results cover public profile fields available at collection time; fields can be null or change later.
- A protected account can expose public profile-header data while keeping its posts private.
- Numeric ID lookup and large batches must pass the same release fixture as handle lookup before a candidate build is published.
- This Actor does not return posts, follower lists, following lists, private data, or a complete history of profile changes.
- One Actor run cannot enforce an account-wide request limit shared with other Actors. The runtime applies its own strict request and time budgets.
- Use the data lawfully and respect applicable privacy, platform, and contractual requirements.

### Support

If an input consistently returns the wrong state or a documented field is missing, open an issue on the Actor's **Issues** tab and include the run ID. Do not post private credentials or personal data in an issue.

### 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 Engaged Audience Exporter · Replies + Retweeters](https://apify.com/data-slayer/twitter-engaged-audience-exporter) |
| [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 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

## `profiles` (type: `array`):

One reference per line. Accepts nasa, @nasa, https://x.com/nasa, https://twitter.com/nasa, or a numeric user ID.

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

Hard cap on unique profile references processed in this run.

## `username` (type: `string`):

Backward-compatible input. Existing API clients can continue sending username exactly as before.

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

Optional compatibility alias for batch handles.

## `profileUrls` (type: `array`):

Optional compatibility alias for batch profile URLs.

## `userIds` (type: `array`):

Optional compatibility alias for stable numeric user IDs.

## Actor input object example

```json
{
  "profiles": [
    "nasa",
    "https://x.com/apify"
  ],
  "maxItems": 100
}
```

# Actor output Schema

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

One dataset item per unique public profile. Existing profile keys are preserved.

## `runSummary` (type: `string`):

Status, termination reason, accepted rows, duplicates skipped, and observed automatic-charge reconciliation.

# 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 = {
    "profiles": [
        "nasa",
        "https://x.com/apify"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("data-slayer/twitter-user").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 = { "profiles": [
        "nasa",
        "https://x.com/apify",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("data-slayer/twitter-user").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 '{
  "profiles": [
    "nasa",
    "https://x.com/apify"
  ]
}' |
apify call data-slayer/twitter-user --silent --output-dataset

```

## MCP server setup

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

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/R4OgEFYrVlIjSUiko/builds/gIUufLEF4yDc6IVtu/openapi.json
