# Threads Profile Scraper - Followers, Bio & Posts by Handle (`headply/threads-profile-scraper`) Actor

Scrape Meta Threads profiles by username: followers, bio, links, verification and recent posts. No login or cookies. Export JSON, CSV or Excel.

- **URL**: https://apify.com/headply/threads-profile-scraper.md
- **Developed by:** [Mayowa Ogedengbe](https://apify.com/headply) (community)
- **Categories:** Social media, Lead generation, Automation
- **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.

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

## Threads Profile Scraper

Scrape [Threads](https://www.threads.com) (Meta) profiles by handle. Returns follower count, bio, bio links, verification status, profile pictures and recent posts as structured JSON.

**No login. No cookies. No account pool.**

***

### What you get

One profile record per handle:

| Field | |
|---|---|
| `username`, `fullName` | Handle and display name |
| `followerCount` | Current follower count |
| `biography` | Bio text |
| `bioLinks` | Outbound links in the bio, with titles |
| `isVerified` | Verification status |
| `isPrivate` | Whether the Threads account is private |
| `profilePicUrl`, `hdProfilePicUrl` | Standard and high-resolution avatars |
| `id`, `url` | Stable numeric id and canonical profile URL |

Plus, unless you turn it off, that account's recent posts with full text, media, and engagement counts.

***

### Input

Handles are accepted in any form.

```json
{
  "profiles": ["zuck", "@mosseri", "https://www.threads.com/@threads"],
  "includeProfilePosts": true,
  "maxPostsPerProfile": 50,
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
```

**Running with no input.** If you start a run without setting anything, the Actor returns a small live sample so you can see the output shape immediately. Set your own keywords, profiles or post URLs for a real run.

Set `includeProfilePosts` to `false` for profile details only. That is faster and cheaper when you are building an account list rather than analysing content.

***

### Output

```json
{
  "type": "profile",
  "id": "63055343223",
  "username": "zuck",
  "fullName": "Mark Zuckerberg",
  "biography": "Mostly superintelligence and MMA takes",
  "bioLinks": [{ "title": "site", "url": "https://example.com" }],
  "followerCount": 5731614,
  "isVerified": true,
  "isPrivate": false,
  "profilePicUrl": "https://...",
  "hdProfilePicUrl": "https://...",
  "url": "https://www.threads.com/@zuck",
  "source": "profile",
  "scrapedAt": "2026-09-10T04:31:00.000Z"
}
```

A run that also returns posts mixes two record shapes in one dataset. **Filter on `type`**, which is `"profile"` or `"post"`. Do not filter on `source`, because a profile's own posts are tagged `source: "profile"` too.

Post records carry `authorUsername` as a flat copy of `author.username`, because spreadsheet and table views cannot read nested paths.

***

### Tracking follower growth

Schedule the Actor with your list of handles and append each run to the same dataset. Every record carries `scrapedAt`, so you get a follower-count time series per account without any extra work.

***

### Pricing

Pay per result. Profiles and posts are billed as separate events, so a profile-only run never pays for post scraping.

***

### Limits, stated plainly

**Post depth.** Threads embeds roughly the first page of an account's posts in the page it serves, about 25. Profile fields themselves are complete.

**Follower lists are not available.** This returns the follower *count*, not the list of followers. Threads does not expose follower lists publicly.

**Proxies.** Threads rate-limits single IP addresses quickly. Residential proxies are strongly recommended beyond a handful of requests.

**Public data only.** A private Threads account returns its profile shell with `isPrivate: true` and no posts.

***

### Legal and compliance

This Actor reads only public Threads pages, the same ones any logged-out visitor can open. It does not log in and does not bypass an access control.

Profiles contain personal data. If you are in the EU or UK, GDPR applies to what you collect and what you do with it, and having a lawful basis is your responsibility as the data controller. Do not resell profile-level personal data as a lead list without the regional carve-outs that apply to you.

***

### Related Actors

- **Threads Scraper** for posts, reply trees, profiles and search in one Actor
- **Threads Keyword Search Scraper** for tracking keywords and brand mentions

***

### FAQ

**Do I need a Threads or Instagram account?**
No. Nothing here authenticates, and there is nowhere to enter credentials.

**Can I get a list of an account's followers?**
No. Threads does not publish follower lists, so no scraper can return them. You get the count.

**What happens with a handle that does not exist?**
The run logs a warning for that handle and continues with the rest. It does not fail the whole run.

**Does this work with threads.net links?**
Yes. Threads moved from threads.net to threads.com, and both forms are accepted, as are bare handles and bare post shortcodes. You do not need to rewrite old links.

**How is this different from the official Threads API?**
Meta's Threads API needs an app, an access token, and it caps keyword search at roughly 500 queries per rolling seven days. This Actor needs none of that and has no weekly quota, because it reads the same public pages a logged-out visitor sees.

**Can I use it from Make, Zapier, n8n or a script?**
Yes. Every Apify Actor is callable over the REST API and through Apify's integrations, and results come back as JSON, CSV or Excel.

**Does it break when Meta ships an update?**
Less often than most. Scrapers that call the internal GraphQL API depend on persisted query ids that Meta rotates without notice. This one reads what Threads server-renders into the page and recognises records by shape rather than by a fixed path.

# Actor input Schema

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

Accepts any form: zuck, @zuck, or https://www.threads.com/@zuck. Returns one profile record per handle, plus that account's recent posts.

## `includeProfilePosts` (type: `boolean`):

Return each account's recent posts alongside its profile record. Turn off for profile details only, which is faster and cheaper.

## `maxPostsPerProfile` (type: `integer`):

Upper bound on posts returned for each profile.

## `searchQueries` (type: `array`):

Keywords to search on Threads in the same run. Every result is tagged with the keyword that found it.

## `postUrls` (type: `array`):

Threads post URLs or shortcodes. Returns each post and its reply tree with conversation depth.

## `searchSort` (type: `string`):

Threads ranks search results either by relevance or by recency. The two orderings return overlapping but different sets, so 'Both' gives the widest coverage at twice the request cost.

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

For each post URL, also scrape its replies with conversation depth. Turn off to fetch the posts alone.

## `maxPostsPerQuery` (type: `integer`):

Upper bound on results returned for each search keyword.

## `maxRepliesPerPost` (type: `integer`):

Upper bound on replies returned for each post. Set to 0 to skip replies entirely.

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

Threads rate-limits single IP addresses quickly. Residential proxies are strongly recommended for anything beyond a handful of requests.

## `maxConcurrency` (type: `integer`):

Parallel requests. Raise for speed, lower if you start seeing blocks.

## `maxRequestRetries` (type: `integer`):

How many times a failed request is retried, with a fresh proxy address each time, before it is given up on.

## Actor input object example

```json
{
  "profiles": [
    "@zuck"
  ],
  "includeProfilePosts": true,
  "maxPostsPerProfile": 100,
  "searchSort": "default",
  "includeReplies": true,
  "maxPostsPerQuery": 100,
  "maxRepliesPerPost": 200,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxConcurrency": 10,
  "maxRequestRetries": 4
}
```

# Actor output Schema

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

Dataset containing all scraped data

# 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": [
        "@zuck"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("headply/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 = { "profiles": ["@zuck"] }

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

```

## MCP server setup

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