# X Profile Metadata Scraper (`automation-lab/x-public-profile-metadata`) Actor

Export public X account identity, audience counts, verification context, and timestamped recent post samples for creator research and CRM enrichment.

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

## Pricing

from $1.55 / 1,000 item extracteds

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

## X Profile Metadata Scraper

Refresh **X profile metadata** for public accounts you already know. Supply X usernames or profile URLs and receive one structured snapshot per account: stable identity, bio, website, join date, audience and activity counts, verification context, profile media, and optional timestamped recent post samples.

Use the records for creator research, account monitoring, audience qualification, and CRM enrichment. No X login, cookies, or API key are requested.

### What does X Profile Metadata Scraper do?

The Actor resolves each supplied public handle through X's anonymous public data surfaces and saves one normalized dataset row per profile found.

It can:

- mix handles such as `NASA` and `@NatGeo` with `x.com` profile URLs;
- deduplicate the same handle case-insensitively;
- capture stable account IDs and current display identity;
- export bio, website, location, join date, and profile media;
- capture follower, following, post, like, media, and list counts;
- expose available verification and protected-account context;
- embed up to 20 recent public post samples in each profile record;
- exclude replies and reposts from samples by default;
- create fresh snapshots suitable for scheduled downstream comparison.

The Actor does not search for unknown accounts, download followers, authenticate to X, maintain history, or calculate changes between runs.

### Who is this X profile metadata scraper for?

#### Creator and influencer researchers

Enrich an existing creator list with current bios, websites, audience size, verification context, and examples of recent public content.

#### Sales and RevOps teams

Resolve profile URLs to stable account IDs before adding public account context to CRM records. Treat self-declared fields as research signals, not verified contact data.

#### Brand and competitive intelligence teams

Schedule repeated snapshots of known brand accounts. Compare exports downstream to detect count, bio, website, or verification changes.

#### Developers and data teams

Call one Actor endpoint instead of maintaining X guest-session requests, response parsing, retries, and output normalization.

### Why use this Actor?

- **Profile plus context:** each row combines account metadata and bounded recent post samples.
- **No credentials:** it does not request an X account, cookie, or private API token.
- **Two input routes:** use usernames, profile URLs, or both in one run.
- **Stable output:** counts are numbers, flags are booleans, nullable context is explicit, and samples are nested typed objects.
- **Cost-aware route:** direct HTTP/API requests with no automatic residential proxy or browser fallback.
- **Honest limits:** invalid inputs fail closed; missing profiles are logged and never emitted as fabricated empty records.

### What X profile data can you extract?

| Field | Meaning |
| --- | --- |
| `accountId` | Stable X account identifier |
| `username`, `url` | Current handle and canonical profile URL |
| `name`, `bio`, `location` | Public display identity and self-declared profile text |
| `website` | Expanded public profile website, or `null` |
| `joinedAt` | Account creation date returned by X |
| `followersCount`, `followingCount` | Current public audience counts |
| `postsCount`, `likesCount`, `mediaCount` | Current activity counters reported by X |
| `listedCount` | Number of public lists containing the account |
| `isVerified`, `isBlueVerified` | Verification flags currently exposed by X |
| `isIdentityVerified` | Identity-verification context when exposed |
| `verifiedSince` | Verification date when exposed, otherwise `null` |
| `verificationType`, `verificationReason` | Additional verification context when exposed |
| `isProtected` | Whether the account's posts are protected |
| `profileImageUrl`, `coverImageUrl` | Public profile media URLs |
| `pinnedPostId` | Pinned post ID when exposed |
| `postSamples` | Bounded array of recent public post samples |
| `postSamplesCount` | Number of samples included in this snapshot |
| `scrapedAt` | ISO 8601 collection timestamp |

Each post sample includes its ID, URL, text, source timestamp, language, engagement counts, reply/repost flags, view count when exposed, and public media URLs.

### How to extract public X profile metadata

1. Open the Actor input page.
2. Add handles under **X usernames**, with or without `@`.
3. Optionally add public x.com or twitter.com URLs under **X profile URLs**.
4. Set **Recent post samples per profile** from `0` to `20`.
5. Decide whether replies or reposts belong in those samples.
6. Set **Maximum profiles** to cap the deduplicated input.
7. Click **Start**.
8. Open the default dataset and export JSON, CSV, Excel, XML, or RSS.

Start with two or three known public accounts. Increase the batch after confirming that the record shape fits your workflow.

### Input parameters

#### `usernames`

Array of public X handles. Accepted values include:

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

Handles follow X's 1–15 character letter, number, and underscore format.

#### `startUrls`

Array of public x.com or twitter.com profile URLs:

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

Post URLs, search URLs, foreign hosts, and reserved X routes fail validation.

#### `maxProfiles`

Maximum unique profiles processed after handles and URLs are combined and deduplicated. Default: `100`. Range: `1–500`.

#### `maxPostSamples`

Maximum recent posts embedded per profile. Default: `5`. Range: `0–20`. Set `0` for a metadata-only run.

#### `includeReplies` and `includeReposts`

Both default to `false`. Enable them only when replies or reposted content are useful for the research job.

### Example input

```json
{
  "usernames": ["NASA", "NatGeo"],
  "startUrls": [{ "url": "https://x.com/esa" }],
  "maxProfiles": 3,
  "maxPostSamples": 3,
  "includeReplies": false,
  "includeReposts": false
}
```

### Example output

Counts and post data change over time. A real public-account run produces this shape:

```json
{
  "accountId": "11348282",
  "username": "NASA",
  "url": "https://x.com/NASA",
  "name": "NASA",
  "bio": "Making the seemingly impossible, possible. ✨",
  "location": "Pale Blue Dot",
  "website": "http://www.nasa.gov/",
  "joinedAt": "Wed Dec 19 20:20:32 +0000 2007",
  "followersCount": 92362533,
  "followingCount": 118,
  "postsCount": 74189,
  "isVerified": false,
  "isBlueVerified": true,
  "isIdentityVerified": false,
  "isProtected": false,
  "postSamples": [
    {
      "id": "2092205524481667467",
      "url": "https://x.com/NASA/status/2092205524481667467",
      "text": "LIVE: We're back with another spacewalk!",
      "createdAt": "Tue Aug 25 11:00:42 +0000 2026",
      "language": "en",
      "replyCount": 662,
      "repostCount": 1706,
      "likeCount": 11388,
      "quoteCount": 184,
      "viewCount": 1407119,
      "isReply": false,
      "isRepost": false,
      "mediaUrls": []
    }
  ],
  "postSamplesCount": 3,
  "scrapedAt": "2026-08-26T06:40:00.000Z"
}
```

### How much does it cost to extract X profile metadata?

The Actor uses pay-per-event pricing:

- a **$0.005** one-time start event per run;
- one **X profile** event for each complete profile record saved;
- BRONZE price: **$0.002588 per saved profile**;
- post samples are included in the profile event and are not charged separately.

At the BRONZE tier, 10 saved profiles cost **$0.03088** including the start event; 100 saved profiles cost **$0.26380**. Lower per-profile tiers apply at higher Apify usage tiers. The Console estimate and active run pricing are the final authority.

Unavailable, malformed, and duplicate profiles do not produce an item event. Apify platform usage may still apply according to your plan.

### Recurring account monitoring workflow

1. Save a Task with a stable list of public handles.
2. Add a daily or weekly Apify schedule.
3. Export every run's default dataset to your warehouse or automation.
4. Match snapshots by `accountId`, not mutable display name.
5. Compare counts, bio, website, verification fields, and recent post IDs downstream.
6. Apply your own material-change rules before alerting a user.

The Actor emits fresh snapshots. It does not persist history, calculate deltas, or send alerts by itself.

### CRM enrichment workflow

- Start from public X URLs already associated with CRM contacts or organizations.
- Set `maxPostSamples` to `0` when only identity and audience context are needed.
- Preserve `accountId` as the stable external key.
- Store `scrapedAt` so users know when the snapshot was collected.
- Keep self-declared bios, websites, and locations labeled as source-provided data.

Do not infer identity, eligibility, influence, or contact consent from a follower count or verification badge alone.

### Limits and failure behavior

- Only supplied public accounts are supported; there is no keyword or user search.
- A run accepts at most 500 unique profiles.
- Each profile embeds at most 20 recent samples from one current timeline response.
- Protected profiles return metadata with an empty sample array.
- Deleted, suspended, unavailable, or nonexistent profiles are logged and omitted.
- If no supplied profile can be resolved, the run fails instead of returning a misleading successful empty dataset.
- X may omit verification details, websites, banners, view counts, or pinned-post IDs; nullable fields remain `null`.
- The direct public route may be rate-limited or changed by X. Retries are bounded; the Actor does not silently switch to paid proxies or user credentials.

### Export and integrations

The default dataset works with Apify integrations and exports:

- CSV or Excel for analyst review;
- JSON for APIs and data pipelines;
- Google Sheets through Make or Zapier;
- webhooks for post-run ingestion;
- SQL warehouses keyed by `accountId`;
- scheduled Task snapshots for downstream monitoring.

Nested `postSamples` are most convenient in JSON. For flat CSV workflows, transform or unnest the array downstream.

### Run with the Apify API

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

#### cURL

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

#### JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/x-public-profile-metadata').call({
  usernames: ['NASA', 'NatGeo'],
  maxProfiles: 2,
  maxPostSamples: 3,
});
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-public-profile-metadata').call(run_input={
    'usernames': ['NASA', 'NatGeo'],
    'maxProfiles': 2,
    'maxPostSamples': 3,
})
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

### Use with Apify MCP

#### Claude Code

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

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

Add this MCP JSON configuration in the client's MCP settings:

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

Example prompts using MCP:

- “Run X Profile Metadata Scraper for NASA and esa with three recent original post samples each.”
- “Resolve these x.com profile URLs and return account IDs, websites, follower counts, and verification context.”
- “Create a current metadata-only snapshot for these handles with zero post samples.”

### Responsible use and legality

Use only public data and follow X's terms, applicable law, and Apify's policies. Respect privacy, intellectual property, database rights, and purpose limitations. Do not use the Actor for harassment, unlawful surveillance, discrimination, identity claims, spam, or decisions that require verified private information.

You are responsible for establishing a lawful basis, honoring deletion and retention duties, and securing exported data. Public availability does not remove every legal or ethical obligation.

### Troubleshooting

#### Why was a profile omitted?

Check that the handle exists, is not a post URL or reserved X route, and is publicly resolvable. Deleted, suspended, and unavailable profiles are omitted. The run log names each unresolved handle.

#### Why is `postSamples` empty?

The account may be protected, have no currently exposed matching original posts, or the input may set `maxPostSamples` to `0`. Enable replies or reposts only if those record types fit the workflow.

#### Why are some verification fields null?

X does not expose the same verification context for every account. Null means the source did not return that optional value; it is not a negative identity determination.

#### What happens during rate limiting?

The Actor retries transient network, 429, and server errors with bounded backoff. Persistent upstream errors fail visibly rather than triggering an unpriced residential or browser fallback.

### FAQ

#### Does this Actor require an X login or API key?

No. It uses anonymous public source data and does not accept X credentials.

#### Can it discover creators by keyword?

No. Supply known usernames or profile URLs. Discovery and search are outside this Actor's scope.

#### Does it scrape complete post history?

No. It embeds a bounded sample of recent public posts for profile context. It is not a historical tweet scraper.

#### Does it track changes automatically?

No. Schedule repeated snapshots and compare them in your own database, spreadsheet, or automation.

#### Are replies and reposts included?

They are excluded by default. Enable `includeReplies` or `includeReposts` when needed.

#### Can I export the results to CSV?

Yes. The default dataset supports Apify's standard exports. JSON preserves nested post samples most naturally.

### Related automation-lab Actors

- [X Profiles Scraper](https://apify.com/automation-lab/x-profile-scraper) for profile-only bulk metadata without embedded post samples.
- [X Profile Emails Scraper](https://apify.com/automation-lab/x-profile-public-email-scraper) for email addresses explicitly displayed in public profile bios.
- [X User Timeline Scraper](https://apify.com/automation-lab/x-user-timeline-scraper) when individual timeline posts, rather than one profile snapshot, are the primary output.

# Actor input Schema

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

Public X handles with or without @. Handles and profile URLs are combined and deduplicated.

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

Public x.com or twitter.com profile URLs to enrich.

## `maxProfiles` (type: `integer`):

Maximum number of unique supplied profiles to process after deduplication.

## `maxPostSamples` (type: `integer`):

Maximum recent public posts embedded in each profile record. Set to 0 for metadata-only enrichment.

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

Include the account's replies among recent post samples.

## `includeReposts` (type: `boolean`):

Include reposts among recent post samples.

## Actor input object example

```json
{
  "usernames": [
    "NASA",
    "NatGeo"
  ],
  "startUrls": [],
  "maxProfiles": 100,
  "maxPostSamples": 5,
  "includeReplies": false,
  "includeReposts": false
}
```

# Actor output Schema

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

Open the default dataset view containing normalized public X profile snapshots.

# 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"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/x-public-profile-metadata").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",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/x-public-profile-metadata").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"
  ]
}' |
apify call automation-lab/x-public-profile-metadata --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/x-public-profile-metadata"
        }
    }
}

```

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/njKvHC1wHJ0aBoTwY/builds/3Rb9XxndBdLDsPyIO/openapi.json
