# Threads Profile & Posts Scraper (`barefoot_grade/threads-profile-scraper`) Actor

Collect public Threads profiles and their latest posts. Paste usernames or profile links to get name, bio, links, exact followers, verified badge and photo, plus each recent post's text, time, likes, replies, reposts and media. Failures are not charged.

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

## Pricing

from $2.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.

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 & Posts Scraper

Turn any public Threads account into clean, structured rows. Paste usernames or profile links and get each profile's name, bio, bio links, exact follower count, verified badge and profile picture, followed by the latest posts shown on the profile: text, post time, likes, replies, reposts, quotes, images and videos. Individual post links work too.

No Threads account is needed. Profiles and posts that cannot be read are listed in the run summary and are not charged.

### Use cases

- **Influencer research**: exact follower counts, bios and links for a list of creators.
- **Brand monitoring**: what a brand or competitor posted recently and how each post performed.
- **Engagement tracking**: likes, replies, reposts and quotes per post, re-run on a schedule to watch them grow.
- **Lead lists**: names, bio links and verified badges for a set of accounts.
- **Content research**: the latest posts, images and videos from accounts in a niche.

### Quick Start

```json
{
  "profiles": ["zuck", "nasa", "https://www.threads.com/@natgeo"],
  "postUrls": ["https://www.threads.com/@mosseri/post/DeZvGAMmu4D"],
  "maxPostsPerProfile": 25,
  "maxItems": 1000
}
```

Each profile becomes one profile row, followed by one row per recent post. Each post link becomes one post row.

### Input

| Input | Type | Default | Meaning |
| --- | --- | --- | --- |
| `profiles` | array | none | Threads usernames (`zuck` or `@zuck`) or profile links (`https://www.threads.com/@zuck`, `threads.net` links work too). Repeated profiles are read once. |
| `postUrls` | array | `[]` | Individual post links (`https://www.threads.com/@user/post/<code>`). A post already returned from its profile is not repeated. |
| `includePosts` | boolean | `true` | Add the latest posts shown on each profile. Turn off for profile rows only. |
| `maxPostsPerProfile` | integer | `25` | Cap on post rows per profile, 1 to 50. |
| `maxItems` | integer | `1000` | Total cap on rows (profiles plus posts) for the whole run, up to 100,000. |

Give at least one profile or post link.

### Example queries

- `{"profiles": ["netflix", "nba", "espn"]}`: three brand accounts and their latest posts.
- `{"profiles": ["mosseri", "zuck"], "includePosts": false}`: profile rows only.
- `{"postUrls": ["https://www.threads.com/@zuck/post/DeZtp-TkQHh"]}`: one post with its current counts.
- `{"profiles": ["natgeo"], "maxPostsPerProfile": 5}`: one profile and at most five posts.

### What it returns

Every row has a `kind`: `profile` or `post`. All rows share the same columns, so profiles and posts export into one sheet; columns that do not apply to a row are `null` (or an empty list).

Profile rows:

| Field | Meaning |
| --- | --- |
| `username`, `url` | The username and the profile link. |
| `fullName` | The display name. |
| `biography` | The bio text. |
| `bioLinks` | Links listed on the profile. |
| `followerCount` | Exact follower count (not rounded). |
| `isVerified` | Whether the account has the verified badge. |
| `isPrivate` | Whether the profile is marked private. |
| `profilePicUrl` | The largest available profile picture. |
| `userId` | The account's numeric ID. |
| `postsReturned` | How many post rows follow for this profile. |

Post rows:

| Field | Meaning |
| --- | --- |
| `url`, `code`, `postId` | The post link, its short code and its numeric ID. |
| `username`, `fullName`, `isVerified`, `userId` | The post's author. |
| `text` | The post text. |
| `createdAt` | When it was posted (UTC, ISO 8601). |
| `likeCount`, `replyCount`, `repostCount`, `quoteCount` | Engagement counts. `likeCount` is `null` when the author hides it. |
| `mediaType` | `text`, `image`, `video` or `carousel`. |
| `images`, `videos` | Image and video links, one per slide for carousels. Videos also carry their cover image. |
| `linkUrl` | The web link a post previews, if any. |
| `quotedPostUrl` | The post this post quotes, if any. |
| `isPinned` | Pinned to the top of the profile. |
| `isReply` | Part of a thread the author continued, or a reply. |
| `isRepost` | Shown on the profile but written by another account. |
| `profileUsername` | The profile the post was found on (`null` for rows from post links). |

Every row also carries `source` (`profile` or `post`), `input` (the value you entered), `scrapedAt` and `error` (always `null` in the dataset).

### Output example

```jsonl
{"kind": "profile", "username": "nasa", "url": "https://www.threads.com/@nasa", "isVerified": true, "userId": "28829152388", "fullName": "NASA", "biography": "Making the seemingly impossible, possible. ✨", "bioLinks": [], "followerCount": 12785923, "isPrivate": false, "profilePicUrl": "https://scontent-hel3-1.cdninstagram.com/v/t51.82787-19/669747085_18089786557960389_922072622069351626_n.jpg", "postsReturned": 5, "postId": null, "code": null, "text": null, "createdAt": null, "likeCount": null, "replyCount": null, "repostCount": null, "quoteCount": null, "mediaType": null, "images": [], "videos": [], "linkUrl": null, "quotedPostUrl": null, "isReply": null, "isPinned": null, "isRepost": null, "profileUsername": "nasa", "source": "profile", "input": "nasa", "scrapedAt": "2026-10-20T01:10:00Z", "error": null}
{"kind": "post", "username": "nasa", "url": "https://www.threads.com/@nasa/post/Decc755lYhC", "isVerified": true, "userId": "28829152388", "fullName": "NASA", "biography": null, "bioLinks": [], "followerCount": null, "isPrivate": null, "profilePicUrl": null, "postsReturned": null, "postId": "4007205030373722178", "code": "Decc755lYhC", "text": "Spotted: views of a \"space jellyfish\" following today's launch of NASA’s SpaceX 35th commercial resupply mission to the International Space Station.", "createdAt": "2026-10-13T18:28:06Z", "likeCount": 41103, "replyCount": 592, "repostCount": 4378, "quoteCount": 282, "mediaType": "carousel", "images": ["https://scontent-hel3-1.cdninstagram.com/v/t51.82787-15/847998870_18123835888960389_7278135639222434691_n.jpg", "https://scontent-hel3-1.cdninstagram.com/v/t51.82787-15/846964916_18123835993960389_2780682481226156847_n.jpg", "https://scontent-hel3-1.cdninstagram.com/v/t51.82787-15/849508659_18123836011960389_1894048710237085880_n.jpg", "https://scontent-hel3-1.cdninstagram.com/v/t51.82787-15/845941405_18123836032960389_8401705155110598071_n.jpg"], "videos": [], "linkUrl": null, "quotedPostUrl": null, "isReply": false, "isPinned": false, "isRepost": false, "profileUsername": "nasa", "source": "profile", "input": "nasa", "scrapedAt": "2026-10-20T01:10:00Z", "error": null}
```

Image links are shortened here; real rows carry the full links.

### Failed profiles and posts

A profile that does not exist, is not publicly visible, or cannot be read after several tries is listed in the run summary (`OUTPUT.sourceErrors`) with a short code such as `NOT_FOUND`, `RATE_LIMITED` or `LOGIN_WALL`, and the run goes on with the rest. These entries are not dataset rows and are not charged. A run in which nothing at all could be read fails with a clear message.

### Limits and caveats

- Threads shows visitors only the first page of a profile, usually 4 to 10 recent posts; older history, replies tabs, follower lists and search are not included.
- Counts are read at run time and change quickly on popular posts.
- Some well-known handles have no public Threads profile under that name (for example `vogue` or `bbcnews`); they are reported as `NOT_FOUND`. Private or restricted profiles may likewise show no posts or be reported as `NOT_FOUND`.
- Media links are the ones Threads serves and expire after some days; download what you need soon after the run.
- Automated access is subject to Threads' terms; use this actor only where you have the necessary permissions and a lawful basis.

### FAQ

**Do I need a Threads or Instagram account?** No. Only public information is collected.

**Can I mix usernames, profile links and post links?** Yes. Put usernames and profile links in `profiles`, post links in `postUrls`. Duplicates are returned once.

**How many posts will I get per profile?** The posts on the first page of the profile, usually 4 to 10, capped by `maxPostsPerProfile`. Setting the cap above about 10 rarely adds more.

**Is the follower count exact?** Yes, `followerCount` is the exact number, not a rounded label like "5.7M".

### Price

**$0.0025 per result** (each profile row and each post row), plus **$0.005 per run start**. The run-start event is charged per GB of memory; the default 512 MB run is one start event. The start is charged even if the run saves no results. Profiles and posts that fail are not charged. Platform usage is included in these prices.

# Actor input Schema

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

Threads usernames (zuck or @zuck) or profile links (https://www.threads.com/@zuck). Each profile becomes one profile row, followed by its latest posts when posts are included.

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

Individual Threads post links (https://www.threads.com/@user/post/<code>). Each link becomes one post row.

## `includePosts` (type: `boolean`):

Add a row for each recent post shown on every profile. Turn off to collect profile rows only.

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

Cap on post rows per profile, 1 to 50. Threads shows visitors only the first page of a profile, usually 4 to 10 recent posts; a higher cap rarely adds more.

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

Total cap on dataset rows (profiles plus posts) across the whole run.

## Actor input object example

```json
{
  "profiles": [
    "zuck",
    "nasa"
  ],
  "postUrls": [],
  "includePosts": true,
  "maxPostsPerProfile": 25,
  "maxItems": 1000
}
```

# Actor output Schema

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

No description

## `summary` (type: `string`):

No description

# 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",
        "nasa"
    ],
    "postUrls": [],
    "includePosts": true,
    "maxPostsPerProfile": 25,
    "maxItems": 1000
};

// Run the Actor and wait for it to finish
const run = await client.actor("barefoot_grade/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",
        "nasa",
    ],
    "postUrls": [],
    "includePosts": True,
    "maxPostsPerProfile": 25,
    "maxItems": 1000,
}

# Run the Actor and wait for it to finish
run = client.actor("barefoot_grade/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",
    "nasa"
  ],
  "postUrls": [],
  "includePosts": true,
  "maxPostsPerProfile": 25,
  "maxItems": 1000
}' |
apify call barefoot_grade/threads-profile-scraper --silent --output-dataset

```

## MCP server setup

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