# Threads Scraper - Posts, Replies, Reposts & Profiles (`danthedataman/threads-scraper`) Actor

Scrape public Threads profiles, posts, replies and reposts with like, reply, repost and quote counts, plus optional views. Find accounts and ranked posts by keyword. No login.

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

## Pricing

from $1.00 / 1,000 post rows

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

Collect public Threads profiles, posts, replies, reposts, single posts by URL, accounts by keyword and top-ranked keyword search results. Use the rows for brand monitoring, creator discovery and content research.

### Try it

The form prefills NASA as a first example. In posts mode it returns one profile row and up to ten posts. The prefill is not an API default: an empty input returns no rows and a guidance message.

Example input:

```json
{"mode":"posts","usernames":["nasa"],"maxPosts":10}
```

For accounts or search, supply keywords instead:

```json
{"mode":"accounts","keywords":["coffee_roaster"],"maxPosts":10}
```

For post mode, supply public post URLs in postUrls. The post is returned without its comment thread. Profile modes accept usernames or profile URLs, including batches.

### Input

| Field | Type | Default | Meaning |
| --- | --- | --- | --- |
| `mode` | string | `posts` | posts, replies, reposts, post, accounts or search. |
| `usernames` | array | None; form prefill NASA | Usernames/profile URLs for the three profile modes. |
| `postUrls` | array | None | Post URLs for post mode. |
| `keywords` | array | None; form prefill coffee | Keywords for accounts or top-ranked search. |
| `maxPosts` | integer | 10 | Maximum content/account rows per target or keyword; the profile row is additional. Zero performs no work. |
| `postedAfter` | string | None | Inclusive UTC lower bound, profile modes only. Date or timestamp with offset. |
| `postedBefore` | string | None | Inclusive UTC upper bound, profile modes only. Date-only includes the whole day. |
| `includeViews` | boolean | false | Fetch a view count from each post page (one extra request per post, billed as a views event). Missing counts stay null and are not charged. |
| `proxyConfiguration` | object | Automatic datacenter | Optional proxy override; no account-specific groups are forced. |

Date bounds apply to the target's own posts and replies, and to the time the target reposted an item. Older reply parents do not count or stop collection. Pinned posts do not end traversal early. Each current thread is processed before stopping at the first unpinned target root older than the lower bound. Self-thread children use their own publication times.

### Output

The dataset contains profile, post and account records. Every record carries recordType, requestedTarget, sourceTab and scrapedAt. requestedTarget keeps what you sent; the author fields hold the resolved identity. Example with values abbreviated:

```json
{"recordType":"post","requestedTarget":"nasa","sourceTab":"posts","scrapedAt":"…","postId":"…","postCode":"…","authorUsername":"nasa","authorUserId":"…","text":"…","takenAt":"…","likes":null}
```

| Record | Fields |
| --- | --- |
| Profile | userId, username, fullName, bio, followers, verified, profilePicture, bioLinks, profileTags, isPrivate, emails, phones. |
| Account | userId, username, fullName, bio, followers, verified, emails, phones. |
| Post identity/content | postId, postCode, url, authorUsername, authorUserId, authorVerified, text, takenAt. |
| Post counts | likes, replies, reposts, quotes, reshares. |
| Media and attachments | mediaType, mediaUrls, topicTag, linkPreview, poll, music, quotedPost, replyToAuthor, repliedToPost. |
| Source metadata | locationName, locationId, language, fediverseEnabled, isEdited, genAiLabel, isPinned, replyControl, isSpoiler, isReply. |
| Reposts | Original post fields plus repostedBy and repostedAt. |
| Views enabled | viewCount and viewCountStatus: available or unavailable. |

IDs are strings. Counts are numbers; missing values are null. Timestamps are UTC ISO strings. mediaType describes the image, video or carousel structure; mediaUrls keep the source variants. emails and phones are strings found in the public bio, unverified. Attachment objects keep the source metadata. Location, language and fediverse fields may be null.

### Status and completeness

Missing and unavailable targets produce explicit uncharged records in ERRORS and per-target status in SUMMARY. A missing account is reported only when the username lookup returns no user. Private and otherwise gated accounts are reported as unavailable_logged_out, without distinguishing them; a source-supplied private flag is retained when available and named in the reason. Renames or a different resolved identity are reported rather than substituted.

SUMMARY reports target content-row counts, pages, collectionStatus, sourceExhausted, total dataset rows, requests, decodedBytes and browserFallbacks. Its per-target rows exclude the additional profile record; its total rows includes every dataset record. A limit, missing/repeated cursor, operation failure, date boundary or browser page limit is distinct from verified source exhaustion. Earlier valid rows survive a later partial read.

### Billing and views

You pay per profile, post and account row, plus one views event per available view count when includeViews is on, plus the Actor start. Status and error records are not charged. Tier prices are on the Pricing tab. Collection stops when a row or views charge reaches your maximum total charge for the run.

In profile and search modes, views cost one extra post-page request per post, paced like every other request, so they lengthen runs: in our measured 10-post NASA run, views raised the run time from about 6 to about 35 seconds. Post mode reuses the page it already read. Views are off by default. Views are never estimated: a missing view count stays null and is not charged.

### Limits and access

- Recent/date-bounded keyword search is not offered; cause unresolved on the anonymous surfaces measured. In our measurement, none of the posts another tool returned as recent appeared in the public ranked window, so sorting or date-filtering that window does not reproduce recent search. Search rejects postedAfter/postedBefore with guidance.
- Search returns one public ranked window, measured at about 12–27 posts per keyword. It is not a search archive. Accounts returns up to ten accounts per keyword; no deeper page is promised.
- Requests are made logged out through Apify datacenter proxies, at least 1.05 seconds apart. Large page transfers can stall. A transient failure gets one retry with a fresh identity; an empty or changed source is reported, not retried.
- In a batch, the first profile loads the full page; later profiles use smaller queries and still return bio links and tags.
- After some non-login blocks, a browser fallback fetches the first page of a profile or search, or a single post. It cannot paginate or search accounts, runs one call at a time at least 1.05 seconds apart, and is counted in SUMMARY as browserFallbacks. Login redirects and unresolved accounts are reported as statuses and do not trigger it.
- A run reads the source for at most 270 seconds, then writes results, and can end partial. Each extra profile in a batch costs three paced queries before its feed, so keep batches small. maxPosts is a ceiling, not a guarantee.
- Signed media URLs expire. This Actor returns links and does not download media.
- Media tabs, profile sitemaps, trending-page collection, logged-in surfaces and comment threads beneath a post are excluded.
- Threads' robots rules disallow automated collection and its Terms prohibit automated extraction and commercial exploitation. Assess your own use.
- Examples use brands, news outlets and public figures. Support, health and recovery communities are not used as examples or defaults.

### Help

Check SUMMARY and ERRORS before treating a short result as an exhausted source. When reporting an issue, send the mode, the target and the run URL. Do not send credentials or cookies.

# Changelog

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

# Actor input Schema

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

Profile posts, authored replies, reposts, one post, matching accounts, or top-ranked keyword posts.

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

Targets for posts, replies and reposts. Omitted or empty means no profile work.

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

Public Threads post URLs for post mode. Replies beneath the post are excluded.

## `keywords` (type: `array`):

Keywords for accounts or top-ranked search. Omitted or empty means no keyword work.

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

Content/account result limit per target or keyword; profile rows are additional. Zero performs no work.

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

Inclusive UTC lower bound for profile modes only; YYYY-MM-DD or an ISO timestamp with offset. Search rejects date bounds.

## `postedBefore` (type: `string`):

Inclusive UTC upper bound for profile modes only; date-only includes the whole day. Search rejects date bounds.

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

Read nullable views from the post page. Profile/search posts need one additional request each; post mode reuses its page. Available values have a separate views event.

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

Automatic Apify datacenter selection without fixed groups, or your proxy override.

## Actor input object example

```json
{
  "mode": "posts",
  "usernames": [
    "nasa"
  ],
  "postUrls": [],
  "keywords": [
    "coffee"
  ],
  "maxPosts": 10,
  "includeViews": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

## `errors` (type: `string`):

Handled request failures, when present; never result rows.

# 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"
    ],
    "postUrls": [],
    "keywords": [
        "coffee"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("danthedataman/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 = {
    "usernames": ["nasa"],
    "postUrls": [],
    "keywords": ["coffee"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("danthedataman/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 '{
  "usernames": [
    "nasa"
  ],
  "postUrls": [],
  "keywords": [
    "coffee"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call danthedataman/threads-scraper --silent --output-dataset

```

## MCP server setup

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