# Threads Scraper: Profiles, Posts, Search, Replies (`sourabhbgp/threads-scraper`) Actor

Scrape Meta Threads profiles, posts, keyword search results, and post replies in one actor. Paste a username, a profile URL, a post URL, or a keyword and the mode is detected for you. No login, no OAuth, no app review.

- **URL**: https://apify.com/sourabhbgp/threads-scraper.md
- **Developed by:** [Sourabh Kumar](https://apify.com/sourabhbgp) (community)
- **Categories:** Social media, AI, Agents
- **Features:** Limited permissions
- **Stats:** 439 total users, 153 monthly users, 100.0% runs succeeded, 2 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 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

### Meta Threads scraper: profiles, full post history, search and replies

Scrape Meta Threads profiles, posts, search results and replies in one actor, with one input field and no login. Paste a username, a post URL or a keyword, and the mode is detected for you.

**$2 per 1,000 results.** No per-run fee, no monthly minimum, no subscription.

Works for public accounts on threads.com worldwide, except the few that hide from search engines (see Limitations). Posts in any language come back unchanged: the actor doesn't translate or strip non-Latin scripts.

It goes deep. A profile page shows only the newest 15 to 33 posts, but posts mode keeps going back through the account's history until it reaches your limit or the account's first post. Replies work the same way: switch on **Get all replies** and the actor pages through thousands of them.

### Why this scraper, vs. Meta's official API or other actors

Meta's Threads API is real and free. Its keyword search is capped at **2,200 queries per rolling 24 hours**, needs OAuth plus app review for the keyword-search permission, and most analytics cover only the developer's *own* posts. That's enough for first-party publishing. It's not enough for monitoring competitors, scraping a competitor's profile, or backfilling historical posts.

Many Apify alternatives cover only one or two of these jobs, and most add a start fee on every run. Here it's one input box for all four.

| Concern | Meta's official API | Most Apify Threads scrapers | This actor |
| --- | --- | --- | --- |
| App registration / OAuth | Required | None | None |
| Search query cap | 2,200 per 24 hours | None | None |
| Modes you get | Publishing + own analytics | Often one or two per actor | All four: profile, posts, search, replies |
| Post history | Your own posts only | Varies | Back to the account's first post |
| Replies extraction | Only on your own posts | Often missing | Yes, on any public post |
| Reply depth | n/a | Whatever the page embeds | Whatever the page embeds, or every reply with one checkbox |
| Per-run start fee | n/a | Common ($0.005 to $0.02) | None |
| Per 1,000 results | Free, but capped | The top-ranked ones: $2.50 to $20 | **$2.00** |

### What data can you extract?

<table>
<tr><td>👤 Username, full name, bio</td><td>✅ Verified flag, follower count</td><td>🖼️ Profile picture (HD)</td><td>🔗 Bio links</td></tr>
<tr><td>📝 Post text + post code</td><td>❤️ Like, repost, quote, reply count</td><td>↗️ Share count</td><td>👁️ View count (post URLs)</td></tr>
<tr><td>📷 Image URLs (single + carousel)</td><td>🎬 Video URLs (direct MP4)</td><td>📌 Pinned status</td><td>✏️ Edited flag</td></tr>
<tr><td>🏷️ Topic tag</td><td>@️⃣ Mentions array</td><td>🌐 URLs array</td><td>🤝 Paid-partnership flag</td></tr>
<tr><td>🔗 Link preview card</td><td>↩️ Reply linkage (who a post replies to)</td><td>🆔 Stable user ID</td><td>📐 Media dimensions</td></tr>
<tr><td>🙋 Author name, ID, verified flag, avatar on every post</td><td>💬 Quoted post</td><td>📊 Poll options and vote counts</td><td>🎵 Song and artist</td></tr>
<tr><td>📍 Tagged location</td><td>🔒 Who can reply</td><td>🎞️ Inline Giphy stickers</td><td>🔎 Real match vs. context in search</td></tr>
</table>

The actor extracts everything Threads serves to a logged-out browser. It does not extract likers lists, follower lists, or per-post analytics. Those live behind login.

#### Profile mode

A single record per username, with the account's newest posts nested inside `posts[]` (15 to 33, depending on the account). Each nested post carries the full post field set. Profile mode doesn't page back through older posts. Use posts mode for that.

#### Posts mode

One flat record per post. It starts with the posts on the profile page, then goes back through the account's older posts until it reaches **Max Results**, your per-input limit, or the account's first post. In testing, one account's entire history (404 posts, back to July 2023) came back in about 2 minutes.

#### Search mode

One record per post, with the same full field set as posts mode. A keyword returns roughly 40 to 60 posts. When the matching post is a reply, Threads also sends the post it replies to, so the reply makes sense. Those rows carry `isSearchMatch: false`. Filter on `isSearchMatch: true` to keep only real matches.

#### Replies mode

One record for the parent post (the only place `viewCount` is populated) plus one record per reply, each carrying the full post field set.

A post page carries only a slice of its replies, sometimes none at all. Turn on **Get all replies** to page through the rest: on one busy post that meant 4,954 rows instead of the 10 on its page. Every reply is a charged result, so set a limit first.

### How to scrape Threads: step by step

1. [Create a free Apify account](https://console.apify.com/sign-up). Takes 30 seconds, no card needed.
2. Open [Threads Scraper](https://console.apify.com/actors/P5oZe4b6Lg8LpvDlN?addFromActorId=P5oZe4b6Lg8LpvDlN) in the Apify Console.
3. Paste any combination of `@usernames`, profile URLs, post URLs, or search keywords into the **URLs** field.
4. Set **Max Results (total)**, and **Max results per input** if you want a fixed number from each account or keyword.
5. Click **Start**. A single profile or keyword usually finishes in 5 to 30 seconds. Going back through hundreds of older posts or thousands of replies takes a few minutes.
6. Export as JSON, CSV, or Excel, or fetch via the Apify API.

### How much does Threads Scraper cost?

Pay-per-result pricing.

- **Per 1,000 results: $2.00**
- Free-plan yield (Apify's $5/month credits): roughly **2,500 results**.
- Starter-plan yield ($29/month): about **14,500 results per month**.
- No per-run fee. No subscription lock-in.

Both limits are spending limits too: you're never charged for more rows than **Max Results (total)** allows. Bad input costs nothing. A typo'd handle or an unsupported link is skipped and reported, not billed.

### Input

Paste anything. The actor figures out the mode.

```json
{
    "urls": [
        "@zuck",
        "https://www.threads.com/@nike",
        "https://www.threads.com/@zuck/post/DeZtp-TkQHh",
        "AI startups",
        "#threads"
    ],
    "maxResults": 0
}
```

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `urls` | string\[] | `["https://www.threads.com/@zuck"]` | Mix of profile URLs, `@usernames`, post URLs, profile `/replies` and `/media` tabs, search keywords or search URLs. Mode is auto-detected per entry. |
| `mode` | enum | (auto) | Override auto-detection. Values: `profile`, `posts`, `search`, `replies`. |
| `maxResults` | integer | `50` | Most rows for the whole run, across every entry, and the most you can be charged for. `0` = no limit. |
| `maxResultsPerInput` | integer | (none) | Most rows from each entry: per account in posts mode, per keyword in search, per post in replies mode. Leave empty for no per-entry limit. |
| `fetchAllReplies` | boolean | `false` | Replies mode only. Page past the handful of replies the post page carries. Ignored by the other modes. |

The two limits work together, and the run stops at whichever is hit first. To get 200 posts from each of 3 accounts, set `maxResultsPerInput` to 200 and `maxResults` to 600 (or 0).

#### Auto-detection rules

- `https://threads.com/@zuck` → profile
- `@zuck` (leading `@` required, ASCII handle ≤30 chars) → profile
- `https://threads.com/@zuck/replies` or `/media` → that tab's posts
- `https://threads.com/@zuck/post/<code>` or a `https://threads.com/t/<code>` short link → replies
- `AI startups`, `#ai`, or a phrase that starts with a handle, like `@nike shoes` → search
- A search URL pasted from the browser → that search, including the Tags tab
- Empty input → runs `@zuck` as a sample

Share-link tracking parameters (`?ref=share`, `?fbclid=...`, `?utm_source=...`) and URL fragments (`#section`) are stripped before parsing, so social-media share links work as-is. The same post or account pasted twice, as a short link, with share parameters, on threads.net or in different capitals, runs and bills once.

### Recipes (ready-to-paste)

#### Get a Threads profile and its latest posts

```json
{ "urls": ["@zuck"], "maxResults": 1 }
```

Returns one profile record with `posts[]` containing the account's newest posts.

#### Get an account's post history

```json
{ "urls": ["@mosseri"], "mode": "posts", "maxResults": 500 }
```

Goes back through older posts until it has 500 or reaches the account's first post. Use `"maxResults": 0` for everything.

#### Get the same number of posts from several accounts

```json
{
    "urls": ["@nike", "@adidas", "@puma"],
    "mode": "posts",
    "maxResultsPerInput": 200,
    "maxResults": 0
}
```

Up to 200 posts from each account, 600 in total.

#### Pull engagement on a specific Threads post

```json
{ "urls": ["https://www.threads.com/@zuck/post/DeZtp-TkQHh"] }
```

Returns the parent post with `viewCount`, `likeCount`, share/repost/quote counts, plus the replies the post page carries.

#### Get every reply on a post, not just the first few

```json
{
    "urls": ["https://www.threads.com/@zuck/post/DeZtp-TkQHh"],
    "fetchAllReplies": true,
    "maxResults": 500
}
```

Pages through the full reply list. Each reply is a charged result, so `maxResults` is what keeps the bill predictable.

#### Search Threads by hashtag or keyword

```json
{ "urls": ["#ai", "AI startups", "Apify"], "maxResultsPerInput": 30, "maxResults": 90 }
```

Each entry runs as a separate search. Keep only `isSearchMatch: true` rows if you don't want the context posts.

#### Bulk-scrape multiple profiles in one run

```json
{ "urls": ["@zuck", "@instagram", "@nike", "@apple"], "maxResults": 0 }
```

One profile record per account. `maxResults: 0` removes the cap.

### Output

Real records copied verbatim from live runs, with every field the mode returns. Long CDN URLs are shortened at the `?` for readability, and the profile example keeps one of its nested posts. A `null` is genuinely null in that mode, never a field dropped to save space.

#### Profile record (auto-detected from `@username` or profile URL)

```json
{
    "type": "profile",
    "username": "zuck",
    "fullName": "Mark Zuckerberg",
    "bio": "Mostly superintelligence and MMA takes",
    "followerCount": 5744949,
    "isVerified": true,
    "profilePicUrl": "https://scontent-iad6-1.cdninstagram.com/v/t51.82787-19/825322135_17989325280103224_1252773933700107438_n.jpg?...",
    "posts": [
        {
            "postCode": "DeZtp-TkQHh",
            "text": "Introducing Muse Wonder, our new family of frontier models with state of the art performance for personal and professional agentic work.",
            "likeCount": 1530,
            "repostCount": 105,
            "quoteCount": 49,
            "replyCount": 225,
            "shareCount": 116,
            "viewCount": null,
            "postedAt": "2026-10-12T16:56:29.000Z",
            "imageUrls": [
                "https://scontent-iad6-1.cdninstagram.com/v/t51.82787-15/844965867_17991705567103224_8296143909108287920_n.webp?..."
            ],
            "postUrl": "https://www.threads.com/@zuck/post/DeZtp-TkQHh",
            "hashtags": [],
            "mentions": [],
            "urls": [],
            "isPaidPartnership": false,
            "isEdited": false,
            "isPinned": false,
            "hasAudio": false,
            "accessibilityCaption": null,
            "videoUrls": [],
            "linkPreview": null,
            "isReply": false,
            "replyToUsername": null,
            "rootPostUsername": null,
            "topicTag": null,
            "mediaWidth": 2160,
            "mediaHeight": 3260,
            "authorId": "63055343223",
            "authorFullName": "Mark Zuckerberg",
            "authorIsVerified": true,
            "authorProfilePicUrl": "https://scontent-iad6-1.cdninstagram.com/v/t51.82787-19/825322135_17989325280103224_1252773933700107438_n.jpg?...",
            "stickerUrls": [],
            "replyControl": "everyone",
            "quotedPost": null,
            "poll": null,
            "music": null,
            "location": null
        }
    ],
    "scrapedAt": "2026-10-13T12:24:12.947Z",
    "url": "https://www.threads.com/@zuck",
    "userId": "63055343223",
    "isPrivate": false,
    "bioLinks": [],
    "profileTags": [
        "AI Threads",
        "UFC Threads",
        "AI",
        "MMA",
        "memes"
    ]
}
```

#### Post record (`mode: "posts"`)

Same fields as a single entry inside `profile.posts[]`, plus `type: "post"`, `username` and `scrapedAt`.

#### Search record (`mode: "search"` or auto-detected)

```json
{
    "type": "search",
    "query": "sourdough",
    "username": "cheffsonni",
    "postCode": "DdpfPEBD2Re",
    "text": "markisa sourdough bread\n🤘🔥🤘",
    "likeCount": 36,
    "postUrl": "https://www.threads.com/@cheffsonni/post/DdpfPEBD2Re",
    "scrapedAt": "2026-10-13T12:24:22.952Z",
    "repostCount": 0,
    "quoteCount": 0,
    "replyCount": 8,
    "shareCount": null,
    "viewCount": null,
    "postedAt": "2026-09-23T23:26:57.000Z",
    "imageUrls": [
        "https://scontent-iad3-1.cdninstagram.com/v/t51.71878-15/821708703_1059028133626792_1648431282156308925_n.jpg?..."
    ],
    "hashtags": [],
    "mentions": [],
    "urls": [],
    "isPaidPartnership": false,
    "isEdited": false,
    "isPinned": false,
    "hasAudio": true,
    "accessibilityCaption": null,
    "videoUrls": [
        "https://scontent-iad3-1.cdninstagram.com/o1/v/t2/f2/m86/AQOggWKdljZgDdcyG9RHMLqDIG03Cnym85JMhuGJaKuOmxVU3j2eRGmcTC3MWySXxTEPLWTY9R7NqM4ss1DriUnCZagLnw0inO6WfZg.mp4?..."
    ],
    "linkPreview": null,
    "isReply": false,
    "replyToUsername": null,
    "rootPostUsername": null,
    "topicTag": null,
    "mediaWidth": 720,
    "mediaHeight": 1280,
    "isSearchMatch": true,
    "authorId": "42396593289",
    "authorFullName": "Cheff Sonni Bakery",
    "authorIsVerified": false,
    "authorProfilePicUrl": "https://scontent-iad6-1.cdninstagram.com/v/t51.82787-19/764881017_18076655090409290_6330035882206804282_n.jpg?...",
    "stickerUrls": [],
    "replyControl": "everyone",
    "quotedPost": null,
    "poll": null,
    "music": null,
    "location": {
        "id": "373605448268596",
        "name": "Markisa"
    }
}
```

Search records carry the same field set as posts mode, so there is no need to re-run a result to get its engagement. `viewCount` is the one exception: it is only available when you scrape a post URL directly.

#### Reply record (auto-detected from `/post/<code>` URL)

```json
{
    "type": "reply",
    "parentPostCode": "DeZtp-TkQHh",
    "parentUsername": "zuck",
    "isParent": false,
    "username": "_randomdev001",
    "text": "Impressive stuff.\nDoes it beat OpenAIs Dots though?",
    "likeCount": 0,
    "viewCount": null,
    "postedAt": "2026-10-12T16:59:36.000Z",
    "postUrl": "https://www.threads.com/@_randomdev001/post/DeZuAywDEWf",
    "scrapedAt": "2026-10-13T12:24:20.078Z",
    "postCode": "DeZuAywDEWf",
    "repostCount": 0,
    "quoteCount": 0,
    "replyCount": 0,
    "shareCount": null,
    "imageUrls": [],
    "hashtags": [],
    "mentions": [],
    "urls": [],
    "isPaidPartnership": false,
    "isEdited": false,
    "isPinned": false,
    "hasAudio": false,
    "accessibilityCaption": null,
    "videoUrls": [],
    "linkPreview": null,
    "isReply": true,
    "replyToUsername": "zuck",
    "rootPostUsername": "zuck",
    "topicTag": null,
    "mediaWidth": null,
    "mediaHeight": null,
    "authorId": "63095976534",
    "authorFullName": "Peter",
    "authorIsVerified": false,
    "authorProfilePicUrl": "https://scontent-iad3-1.cdninstagram.com/v/t51.82787-19/641717925_17951034903096535_856164541309490688_n.jpg?...",
    "stickerUrls": [],
    "replyControl": "everyone",
    "quotedPost": null,
    "poll": null,
    "music": null,
    "location": null
}
```

The parent record (`isParent: true`) is the only row that carries `viewCount`, on text and video posts alike. Reply rows have `viewCount: null`, because Threads publishes a view count on the post you requested and not on each reply beneath it.

### Field availability by mode

| Field | profile | posts | search | reply (parent) | reply (child) |
| --- | :-: | :-: | :-: | :-: | :-: |
| `type` / `username` / `scrapedAt` | ✅ | ✅ | ✅ | ✅ | ✅ |
| `text` / `postCode` / `postUrl` / `postedAt` | nested | ✅ | ✅ | ✅ | ✅ |
| `likeCount` / `repostCount` / `quoteCount` / `replyCount` / `shareCount` | nested | ✅ | ✅ | ✅ | ✅ |
| `viewCount` | - | - | - | ✅ | - |
| `hashtags` / `mentions` / `urls` / `linkPreview` / `topicTag` | nested | ✅ | ✅ | ✅ | ✅ |
| `isReply` / `replyToUsername` / `rootPostUsername` | nested | ✅ | ✅ | ✅ | ✅ |
| `isPaidPartnership` / `isEdited` / `isPinned` / `hasAudio` / `accessibilityCaption` | nested | ✅ | ✅ | ✅ | ✅ |
| `imageUrls` / `videoUrls` / `mediaWidth` / `mediaHeight` | nested | ✅ | ✅ | ✅ | ✅ |
| `authorId` / `authorFullName` / `authorIsVerified` / `authorProfilePicUrl` | nested | ✅ | ✅ | ✅ | ✅ |
| `stickerUrls` / `replyControl` / `quotedPost` / `poll` / `music` / `location` | nested | ✅ | ✅ | ✅ | ✅ |
| `isSearchMatch` / `query` | - | - | ✅ | - | - |
| `parentPostCode` / `parentUsername` / `isParent` | - | - | - | ✅ | ✅ |
| `followerCount` / `bio` / `profilePicUrl` / `fullName` / `isVerified` / `url` | ✅ | - | - | - | - |
| `userId` / `isPrivate` / `bioLinks` / `profileTags` | ✅ | - | - | - | - |

"nested" means the field appears inside the profile record's `posts[]` array, not at the top level.

A few nulls are the truth about the post, not gaps:

- `mediaWidth` and `mediaHeight` are `null` on text-only posts. There's no media to measure.
- `likeCount` is `null` when the author hides like counts. Threads shows no number, so neither do we.
- `quotedPost`, `poll`, `music` and `location` are `null` unless the post has one. Most don't.
- `shareCount` is usually `null` on replies. Threads rarely reports reshares of a reply.
- `hashtags` is usually empty. Threads has largely moved from inline `#hashtags` to a single topic tag per post, which is what `topicTag` gives you.

### Limitations

- **Accounts hidden from search engines can't be scraped.** Some accounts (we've seen it on a few news brands) turn off search-engine visibility, and Threads then shows them only to logged-in visitors. The run reports them as not available, at no charge.
- **Search returns roughly 40 to 60 posts per keyword.** That's what Threads shows a logged-out visitor, and it's Threads' own Top ranking. A Recent sort and date filters aren't available.
- **`viewCount` exists only on a post you scrape by URL.** Feeds, search results and individual replies don't carry it.
- **The `/media` and `/replies` profile tabs return their first page only.** Use the profile URL in posts mode to go further back.
- **The Reposts tab isn't supported.** A reposts URL is reported as unsupported and not billed.
- **Very deep runs can stop early.** Threads limits how fast one server can page. When that happens you keep every row collected so far, and the run's status message says it stopped early and why.

### FAQ

#### How much does Threads Scraper cost?

Threads Scraper uses pay-per-result pricing. You pay **$2 for 1,000 results**. The Apify Free plan gives you $5 in usage credits a month, enough for around 2,500 results. If you run regularly, the $29/month Starter plan covers about 14,500 results.

No subscription lock-in. Pause whenever.

#### How do I know whether a run got everything?

Read the run's status message. A complete run starts with "Delivered", for example "Delivered 50 results" or "Delivered 404 of 500 requested. That is everything Threads returned for these inputs". If something stopped it short (a hidden account, your charging limit, the run's timeout), the message starts with a short code and says how many inputs were affected and why. The run's key-value store also has a `RUN_SUMMARY` record with the outcome of every input you sent.

#### Is it legal to scrape Threads?

Scraping public data is generally allowed in the US and most of the EU, as long as you don't collect personal data covered by GDPR or CCPA without a lawful basis. This actor only touches publicly accessible pages: anything you'd see in a browser without logging in. How you use the output is on you.

Apify's full breakdown: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/).

#### Can I integrate Threads Scraper with other tools?

Push results into **Make, Zapier, Slack, Airbyte, GitHub, Google Sheets, Google Drive**, and more. Apify treats every actor as a webhook source, so anything that consumes webhooks or pulls from an API works.

Full list: [Apify integrations](https://docs.apify.com/platform/integrations).

#### Can I use Threads Scraper with the Apify API?

Yes. Every run is available via the Apify REST API:

```bash
curl -X POST "https://api.apify.com/v2/acts/sourabhbgp~threads-scraper/runs?token=APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["@zuck"], "maxResults": 1}'
```

Docs: [Apify API reference](https://docs.apify.com/api/v2).

#### Can I use Threads Scraper through an MCP Server?

Yes. Apify ships an MCP server that exposes every actor as a tool, so Claude Desktop, Cursor, and any other MCP-capable client can call Threads Scraper directly. Setup: [Apify MCP docs](https://docs.apify.com/platform/integrations/mcp).

### Your feedback

Bug, missing field, or odd behavior? Drop a note in the [Issues tab](https://console.apify.com/actors/P5oZe4b6Lg8LpvDlN/issues). Reports go to a human and fixes usually ship the same week.

# Actor input Schema

## `urls` (type: `array`):

Paste any mix of Threads URLs, @usernames, or search keywords. The mode is detected for each entry. Accepted: @instagram, https://www.threads.com/@zuck, a post URL, a profile /replies or /media tab, or a plain keyword like AI startups. Note that a username needs its leading @, otherwise it is treated as a search keyword.

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

Leave empty to detect the mode from each entry, which is what most runs want. Set it to force one mode for every entry, and entries that do not fit it are skipped.

## `maxResults` (type: `integer`):

Most rows for the whole run, across every entry, and the most you can be charged for. Set 0 for no limit. Posts mode pages back through an account's older posts until this is reached or the account runs out.

## `maxResultsPerInput` (type: `integer`):

Most rows from EACH entry: per account in posts mode, per keyword in search, per post in replies mode. Leave empty for no per-entry limit. Max Results (total) still caps the whole run, so to get 200 from each of 3 accounts set this to 200 and the total to 600 or 0.

## `fetchAllReplies` (type: `boolean`):

Off by default. A post page carries only a small slice of its replies, sometimes none at all, so a replies run returns roughly that many. Turn this on to page through the rest, which can be hundreds or thousands on a busy post. Every reply returned is a charged result, so set Max Results to the number you actually want before turning this on. Ignored by the other modes.

## Actor input object example

```json
{
  "urls": [
    "https://www.threads.com/@zuck"
  ],
  "maxResults": 50,
  "fetchAllReplies": false
}
```

# Actor output Schema

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

All rows from the run. Post, search and reply rows share the same field set: text, like/repost/quote/reply/share counts, posted time, image and video URLs, link preview card, hashtags, mentions, links, topic tag, reply linkage (isReply, replyToUsername, rootPostUsername), media dimensions, pinned/edited/paid-partnership flags, the post's author (authorId, authorFullName, authorIsVerified, authorProfilePicUrl), stickerUrls, replyControl, quotedPost, poll, music and location. Search rows add query and isSearchMatch (false for the post a matching reply answers). Reply rows add parentPostCode, parentUsername and isParent. Profile rows add follower count, bio, bio links, profile tags, stable user ID and private flag, with the account's newest posts nested in posts\[]. viewCount is populated only on the parent post when you scrape a post URL. Posts mode pages back through older posts until Max Results, the per-input limit or the account's first post; replies mode pages through every reply when fetchAllReplies is on.

## `resultsCsv` (type: `string`):

The same rows exported as CSV, ready for Excel or Google Sheets. Array fields such as imageUrls and videoUrls are expanded into numbered columns, so read the file by column header rather than by position.

# 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 = {
    "urls": [
        "https://www.threads.com/@zuck"
    ]
};

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

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

```

## MCP server setup

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