# Threads Profile Scraper — Followers, Bio, Links, Emails (`lergassy/threads-profile-scraper`) Actor

Every public Threads profile as a row: follower count, full name, bio, bio links, website, emails and phones from the bio, verification, HD avatar, linked Instagram and the latest post. The account's own posts in the same run. No login, no browser.

- **URL**: https://apify.com/lergassy/threads-profile-scraper.md
- **Developed by:** [Matvey](https://apify.com/lergassy) (community)
- **Categories:** Social media, Agents, MCP servers
- **Features:** Limited permissions
- **Stats:** 48 total users, 18 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $1.40 / 1,000 posts

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

**Threads Profile Scraper** turns a list of usernames into full public profiles: follower count, full name, biography, the links in the bio, the website, the emails and phone numbers written in the bio, verification, private flag, the HD avatar, the linked Instagram account and the latest post with its text and date. Ask for the account's own posts in the same run and they arrive alongside. No login, no cookies, no browser.

![One run of Threads Profile Scraper: profiles with followers, bio, links and contacts.](https://raw.githubusercontent.com/lergassy/apify-actor-assets/main/threads-scraper/threads-scraper-output-table.png)

Paste usernames or profile URLs, click Start, export as JSON, CSV or Excel — or call it from the API and from AI agents.

### Tested head-to-head — 24 September 2026

![Tested against 4 other Threads profile Actors: correct Threads follower counts for all five accounts, the latest post's date in every row, and the lowest bill for the request](https://raw.githubusercontent.com/lergassy/apify-actor-assets/main/benchmarks/threadsprofile-tested-2026-09-24.png)

The same request went to this Actor and to the four most-used Actors on the Apify Store that return a Threads profile by username, on the same afternoon from a fresh free account: five public accounts (zuck, mosseri, nasa, natgeo, nytimes), one row each. Follower counts were checked against what Threads itself shows.

| | This Actor | The 4 others |
|---|---|---|
| Accounts with the correct Threads follower count | **5 of 5** | 5 of 5 at two; Instagram's count at one; nothing at one |
| Date of the latest post in the row | **Yes** | Only one of the four |
| What this request cost | **$0.020** | $0.021 – $0.045 (the one that returned nothing cost $0) |

### What is it for?

Influencer and creator research (who has the audience, and is the account alive), lead generation from bio contacts, competitor tracking, and AI agents asked "who is this account". Threads' official API only covers your own account; this Actor reads the public profile pages Threads serves to any visitor.

| Mode | You give | You get |
|---|---|---|
| **Profile** | usernames or profile URLs | the full profile row below |
| **Posts** | usernames | the account's own posts, paged through the whole profile |

### What data does it return?

| Field | Example |
|---|---|
| `username`, `userId`, `profileUrl` | zuck · 63055343223 · https://www.threads.net/@zuck |
| `fullName`, `biography` | Mark Zuckerberg · "Building things…" |
| `followerCount` | 4183562 |
| `bioLinks`, `websiteUrl` | \[{url, title}] · https://… |
| `emails`, `phones` | pulled out of the bio text, ready for outreach |
| `isVerified`, `isPrivate` | true · false |
| `profilePicUrl`, `instagramUrl` | HD avatar · the linked Instagram profile |
| `latestPostAt`, `latestPostUrl`, `latestPostText` | is the account still posting, and about what |

Post rows (Posts mode) carry `id`, `code`, `url`, `text`, `language`, `createdAt`, author fields, `likeCount`, `replyCount`, `repostCount`, `quoteCount`, `shareCount`, `viewCount` (read from each post's own page), media URLs, `hashtags`, `mentions`, `urls`, `linkPreview`, the quoted or reposted post, `isPinned`, `isEdited` and thread position.

### How much does it cost?

Pay per row, no start fee, and error rows are free. There is no browser here, so platform usage is close to zero.

| Row | Price |
|---|---|
| Profile | $0.004 — 1,000 profiles for $4 |
| Post (Posts mode) | $0.002 |

Larger monthly plans get 10–30 % off.

#### Bulk export: what 50,000 profiles actually cost

This Actor is built for bulk jobs — put hundreds of inputs into one run, or call it from the API on
a schedule. There is **no fee per run, no fee per page and no proxy charge**: you pay for the rows
you keep, and error rows are free. That is what decides the bill once you pull a whole market
rather than a single account.

| Job | This Actor | Most-used Actor in this category |
|---|---|---|
| 50,000 profiles across 100 runs | **$200** | $252 |

Checked on the Apify Store on 24 September 2026 against the Actor with the most monthly users in
this category; its per-run fee is counted in, as ours would be if we charged one. Some Actors here
ask less per row — this table compares against the one buyers actually use most.

### How to scrape Threads profiles

1. Put the accounts in **👤 Usernames** — `zuck`, `@natgeo`, or a full `threads.net/@name` link, one per line.
2. Leave **🧭 What to get** on *profile* for one row per account, or switch to *posts* to page through what the account has written.
3. Keep **👤 Full profiles** on. With it off you get only what the account list already carries, and no contacts.
4. Click **Start**. Export as JSON, CSV or Excel, or read the dataset from the API.

### ⬇️ Input

```json
{
  "mode": "profile",
  "usernames": ["zuck", "natgeo", "nasa"],
  "includeProfileDetails": true,
  "maxItems": 100
}
```

Posts of an account, newest first, with a profile row on top:

```json
{ "mode": "posts", "usernames": ["mkbhd"], "maxPosts": 100, "includeProfile": true }
```

Only the posts that mention something, published since a date:

```json
{ "mode": "posts", "usernames": ["natgeo"], "maxPosts": 200, "postedAfter": "2026-09-01", "filterKeywords": ["ocean"] }
```

#### Every input field

| Field | What it does |
|---|---|
| `mode` | `profile` — one row per account. `posts` — the account's own posts. |
| `usernames` | Accounts to read. `zuck`, `@zuck` and the profile URL all work. |
| `startUrls` | Profile links instead of usernames, for when your list is already URLs. |
| `maxPosts` | Posts per account in posts mode. |
| `postedAfter` | Skip posts older than this date — turns a repeat run into monitoring. |
| `filterKeywords` | Keep only posts containing one of these words. Filtering happens before billing. |
| `includeProfile` | Add a profile row alongside the posts. |
| `includeProfileDetails` | Open each profile page for followers, bio, links and contacts. Leave on. |
| `includeViews` | Fill `viewCount` on posts from each post's page (on by default, no extra charge). Turn off for the fastest bulk runs. |
| `maxItems` | Hard ceiling on rows for the whole run — your budget. |
| `concurrency` | Accounts read in parallel. Four is polite and fast enough. |

### ⬆️ Output

```json
{
  "type": "profile",
  "username": "natgeo",
  "userId": "63454848350",
  "fullName": "National Geographic",
  "biography": "Taking our understanding and awareness of the world further.",
  "followerCount": 2100000,
  "bioLinks": [{ "url": "https://on.natgeo.com/threads", "title": "on.natgeo.com" }],
  "websiteUrl": "https://on.natgeo.com/threads",
  "emails": [],
  "phones": [],
  "isVerified": true,
  "isPrivate": false,
  "profilePicUrl": "https://…",
  "instagramUrl": "https://www.instagram.com/natgeo",
  "latestPostAt": "2026-09-14T18:20:11.000Z",
  "latestPostUrl": "https://www.threads.net/@natgeo/post/DdRSOdDjetX",
  "scrapedAt": "2026-09-15T09:00:00.000Z"
}
```

An account that does not exist, or that Threads refuses, arrives as a `type: "error"` row with the reason. Error rows are free and the run still finishes green.

### Use cases

#### Influencer and creator research

Pull a shortlist of accounts and sort by `followerCount`, then use `latestPostAt` to drop the ones that stopped posting months ago.

#### Lead generation from bios

`emails`, `phones`, `websiteUrl` and `bioLinks` are extracted from the bio text, which is where small businesses and creators actually publish their contacts.

#### Competitor tracking

Run the same username list on a schedule and watch follower counts and bio changes move over weeks.

#### Audience and content audit

Switch to posts mode and read an account's whole output with engagement counts, to see which topics earned replies.

#### AI agents

An agent asked "how big is this account and how do I contact them" gets both from a single profile row.

### 🤖 For AI agents and LLM apps

Compact reference for agents calling this Actor through the [Apify MCP server](https://mcp.apify.com) or the API (`lergassy/threads-profile-scraper`).

**Purpose:** resolve a Threads handle into a full public profile — size, bio, links, contacts — and optionally its posts.

**Minimal input:**

```json
{ "mode": "profile", "usernames": ["zuck"], "includeProfileDetails": true }
```

**Behaviours an agent should know:**

- `followerCount` is the number to quote for reach; `latestPostAt` tells you whether the account is alive.
- Contacts come from the bio only. An empty `emails` array means the account published none, not that the lookup failed.
- A private account returns its public header with `isPrivate: true` and no posts. That is the complete answer, not a failure.
- A handle that does not exist returns an error row, free of charge — check `type` before reading fields.
- Billing is per row: one profile row per account, plus one row per post in posts mode. Set `maxItems` to cap the spend.
- No login, cookies or API key are involved, so nothing expires between runs.

### Use via API

Run this Actor from your own code or pipeline. Get your token in Apify Console → Settings → API & Integrations. Every input field below has the same name as in the JSON tab of the input form.

**Python**

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("lergassy/threads-profile-scraper").call(run_input={
    "mode": "profile",
    "usernames": [
        "zuck"
    ],
    "maxPosts": 100,
    "includeProfileDetails": True
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

**JavaScript**

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

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('lergassy/threads-profile-scraper').call({
    "mode": "profile",
    "usernames": [
        "zuck"
    ],
    "maxPosts": 100,
    "includeProfileDetails": true
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

**cURL** (runs the Actor and returns the results in one call)

```bash
curl -X POST "https://api.apify.com/v2/acts/lergassy~threads-profile-scraper/run-sync-get-dataset-items?token=<YOUR_API_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"mode": "profile", "usernames": ["zuck"], "maxPosts": 100, "includeProfileDetails": true}'
```

### Limitations, stated plainly

- **Public data only.** Follower lists, following lists and anything behind a private account are not available to a logged-out visitor and are not returned here.
- **Counts are what the page shows.** Threads rounds large numbers on some surfaces; the Actor reports the figure the profile serves.
- **Contacts are only as good as the bio.** No email guessing, no pattern invention — if it is not written on the profile, it is not in the row.
- **Posts mode reads the account's own posts.** Replies, reposts and whole conversations live in [Threads Replies Scraper](https://apify.com/lergassy/threads-replies-scraper).

### Integrations

Runs from the Apify API, the Python and JavaScript clients, and from **n8n**, **Make** or **Zapier** through the Apify app. Schedule it and push rows into **Google Sheets** or your own webhook. AI agents reach it through the Apify MCP server with no extra setup.

### ❓ FAQ

#### Do I need a Threads or Instagram account?

No. The Actor reads the public profile pages Threads serves to any visitor — no login, no cookies, no tokens to refresh.

#### Can I get followers or following lists?

No. Threads does not show those to a logged-out visitor, so no honest scraper can return them.

#### Where do the emails and phone numbers come from?

From the bio text and the bio links. They are extracted, never guessed. If you need work addresses derived from a company domain, that is [Email Finder](https://apify.com/lergassy/email-finder-api).

#### What happens with a username that does not exist?

You get an error row saying so, free of charge, and the rest of the list is still scraped.

#### How many accounts can one run handle?

Thousands. Profiles are read a few at a time; `maxItems` is what actually limits the run.

#### Is a private account still worth a row?

It returns the public header — name, avatar, follower count, `isPrivate: true` — and no posts. Many buyers use exactly that to filter a list.

#### How do I track changes over time?

Schedule the run daily or weekly on the same username list. Each run appends a snapshot with `scrapedAt`, and the differences are your trend.

#### Is scraping Threads legal?

The Actor reads public pages at a normal rate without logging in, which is ordinary public-data collection. What you do with personal data afterwards is your responsibility — GDPR and similar rules apply to you, not to the page.

### You might also like

| Actor | What it does |
|---|---|
| [Threads Scraper](https://apify.com/lergassy/threads-scraper) | All modes in one: search, posts, replies, profiles |
| [Threads Search Scraper](https://apify.com/lergassy/threads-search-scraper) | Keyword and hashtag search with filters |
| [Threads Replies Scraper](https://apify.com/lergassy/threads-replies-scraper) | Replies, reposts and whole conversations |
| [Email Finder](https://apify.com/lergassy/email-finder-api) | Work email addresses from names and company domains |

### Also known as

People look for this Actor as a Threads profile scraper, a Threads user API, Threads follower count checker, Threads bio scraper, Threads contact extractor and a Threads influencer research tool.

### Notes

Public accounts only: a private profile returns its public header, never its posts. A username that does not exist comes back as an error row, and error rows are free.

Looking for posts by keyword, or for replies and whole conversations? Those live in **Threads Search Scraper**, **Threads Replies Scraper** and the all-in-one **Threads Scraper**.

# Changelog

This Actor's version history is a separate document: https://apify.com/lergassy/threads-profile-scraper/changelog.md

# Actor input Schema

## `mode` (type: `string`):

<b>Posts</b> — an account's own posts, as many as you ask for. <b>Replies</b> / <b>Reposts</b> — what an account answered or boosted. <b>Profile</b> — followers, bio, links and contacts. <b>Search</b> — public posts for keywords and hashtags. <b>Thread</b> — one post with its replies. <b>Accounts</b> — people and brands matching a keyword.

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

For Posts, Replies, Reposts and Profile. Bare name, with @, or the profile URL: <code>zuck</code>, <code>@natgeo</code>, <code>https://www.threads.net/@nasa</code>.

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

Profile URLs (threads.com/@username) — the account is taken from the link. Search, tag and single-post links are not read by this Actor: use Threads Search Scraper for keywords and Threads Replies Scraper for one post.

## `maxPosts` (type: `integer`):

Cap per username or keyword, not per run. Posts mode pages through the whole profile; Search returns what Threads shows a logged-out visitor (usually 20–60 posts per keyword across the top, recent and tag pages).

## `postedAfter` (type: `string`):

<code>YYYY-MM-DD</code>. Older posts are dropped and Posts mode stops paging once it reaches them.

## `filterKeywords` (type: `array`):

Case-insensitive words or phrases; a post is kept when it contains any of them. Empty = keep everything.

## `includeProfile` (type: `boolean`):

Posts, Replies and Reposts modes: also save the account's profile (followers, bio, links, contacts).

## `includeProfileDetails` (type: `boolean`):

Accounts mode: open each account's page for follower count, bio links and contacts (one extra request per account).

## `includeViews` (type: `boolean`):

Fill viewCount on every post (the number Threads shows under a post, e.g. "134K views"). Read from each post's own page: one extra request per post, no extra charge. Turn off for the fastest possible bulk runs.

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

Stop after this many rows in the run.

## `concurrency` (type: `integer`):

How many accounts or keywords are processed at once.

## `proxyConfiguration` (type: `object`):

Apify datacenter proxies work for Threads. If runs end with rate-limit error rows, switch to Residential.

## Actor input object example

```json
{
  "mode": "profile",
  "usernames": [
    "zuck"
  ],
  "maxPosts": 100,
  "includeProfile": false,
  "includeProfileDetails": true,
  "includeViews": true,
  "maxItems": 10000,
  "concurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `rows` (type: `string`):

One row per post (text, author, time, likes, replies, reposts, quotes, shares, media URLs, links, mentions, hashtags, quoted or reposted post, reply context) or per profile / account (followers, bio, links, emails, phones).

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

JSON counters for the run: rows delivered, filtered out, errors and request statistics.

# 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 = {
    "mode": "profile",
    "usernames": [
        "zuck"
    ],
    "includeProfileDetails": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("lergassy/threads-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 = {
    "mode": "profile",
    "usernames": ["zuck"],
    "includeProfileDetails": True,
}

# Run the Actor and wait for it to finish
run = client.actor("lergassy/threads-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 '{
  "mode": "profile",
  "usernames": [
    "zuck"
  ],
  "includeProfileDetails": true
}' |
apify call lergassy/threads-profile-scraper --silent --output-dataset

```

## MCP server setup

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