# Threads Scraper API - Posts, Profiles & Search (`webdata_labs/threads-scraper`) Actor

\[$3.00 / 1K] Scrape public Meta Threads posts, profiles, keyword search results, engagement metrics, media, hashtags, mentions, and timestamps without a Threads login.

- **URL**: https://apify.com/webdata_labs/threads-scraper.md
- **Developed by:** [WebData Labs](https://apify.com/webdata_labs) (community)
- **Categories:** Social media, Lead generation, Automation
- **Features:** Limited permissions
- **Stats:** 319 total users, 113 monthly users, 98.9% runs succeeded, 2 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $1.56 / 1,000 threads 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 Scraper - Posts, Profiles & Search

**Extract public Meta Threads posts, profiles, and keyword search results without a Threads login.** Get clean structured rows for content monitoring, creator research, PR analysis, and data pipelines.

Use the Actor from Apify Console, schedule recurring runs, download JSON/CSV/Excel, or call it through the Apify API and MCP.

### ✅ What you get

- Public profile metadata with exact follower counts when Threads exposes them
- Deep post history per profile - hundreds of posts, not the handful the public page renders
- Public posts with full text, publication timestamps, and canonical URLs
- Likes, direct replies, reposts, and quote counts
- Images, videos, carousel items, dimensions, and video thumbnails
- Parsed hashtags, mentions, and absolute URLs
- Keyword search results with the source query attached to every row
- Consistent `profile` and `post` result types in one dataset

### 🔎 Why use this Threads scraper

The public Threads profile page renders only a handful of posts, which is where most Threads scrapers stop. This Actor follows the same paginated feed the site itself uses, so `maxPosts` is a number you actually reach: a single profile returns hundreds of posts going back months.

It runs over plain HTTP with no browser, so runs are fast and cheap, and a recursive extractor normalizes Threads' deeply nested payloads into stable fields even when Meta reshuffles the wrapper paths.

The result is ready for:

- Brand mention monitoring
- Competitor and executive account tracking
- Creator and influencer discovery
- Campaign and content research
- Academic NLP datasets built from public content
- Scheduled exports to Sheets, data warehouses, or webhooks

### 📊 What data you get

| Field            | Type   | Description                                |
| ---------------- | ------ | ------------------------------------------ |
| `type`           | string | `profile` or `post`                        |
| `username`       | string | Threads account username                   |
| `fullName`       | string | Public display name                        |
| `followerCount`  | number | Exact public follower count when available |
| `text`           | string | Full public post text                      |
| `date`           | string | ISO 8601 publication time                  |
| `likeCount`      | number | Visible likes                              |
| `replyCount`     | number | Visible direct replies                     |
| `repostCount`    | number | Visible reposts                            |
| `quoteCount`     | number | Visible quote posts                        |
| `media`          | array  | Normalized image/video attachments         |
| `hashtags`       | array  | Hashtags parsed from the post text         |
| `mentions`       | array  | Mentioned usernames                        |
| `url`            | string | Canonical Threads profile or post URL      |
| `sourceUsername` | string | Input username that produced the row       |
| `searchQuery`    | string | Input keyword that produced a search row   |
| `scrapedAt`      | string | ISO 8601 collection time                   |

### 👥 Who it's for

- Social media and brand teams monitoring public conversations
- PR agencies tracking spokespeople, journalists, and campaign mentions
- Researchers collecting public Threads data for analysis
- Data teams feeding dashboards, warehouses, and AI workflows
- Developers who need a simple Threads scraper API instead of maintaining browser extraction

### ⚙️ How to scrape Threads

1. Open the Actor in Apify Console.
2. Choose `Profiles`, `Profile posts`, or `Keyword search`.
3. Enter up to 20 usernames/profile URLs or up to 20 search queries.
4. Set `maxPosts` to how many posts per seed you want. Start at `5` to check the output shape cheaply.
5. Run the Actor and inspect the dataset. Network routing is managed automatically.
6. Download results or connect a schedule, webhook, Make, Zapier, or API client.

### 📥 Input

Profile posts example:

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

Keyword search example:

```json
{
    "mode": "search",
    "searchQueries": ["artificial intelligence", "product launch"],
    "maxPosts": 25,
    "postedAfter": "2026-08-01T00:00:00Z"
}
```

| Input            | Type     | Default | Description                                                                                                                                                |
| ---------------- | -------- | ------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `mode`           | string   | `posts` | `profile`, `posts`, or `search`                                                                                                                            |
| `usernames`      | string\[] |       - | Usernames or profile URLs for profile/posts mode. Required unless mode is `search`                                                                         |
| `searchQueries`  | string\[] |       - | Keywords for search mode. Required when mode is `search`                                                                                                   |
| `maxPosts`       | integer  |    `25` | Maximum post rows per username/query, 1 to 500. Posts mode pages until it hits this number or the profile runs out; keyword search is one page of about 20 |
| `postedAfter`    | string   |       - | Inclusive ISO 8601 lower date bound. In posts mode the Actor stops paging once it passes this date                                                         |
| `postedBefore`   | string   |       - | Exclusive ISO 8601 upper date bound                                                                                                                        |
| `includeProfile` | boolean  |  `true` | Add one profile row in posts mode                                                                                                                          |

`usernames` and `searchQueries` have no defaults on purpose: an empty one fails the run with a clear message instead of quietly scraping something you did not ask for and billing you for it.

### 📤 Output

```json
{
    "type": "post",
    "postId": "3912345678901234567",
    "code": "ExampleCode1",
    "username": "exampleuser",
    "fullName": "Example Creator",
    "isVerified": true,
    "text": "A sample public post about a product launch.",
    "likeCount": 420,
    "replyCount": 35,
    "repostCount": 18,
    "quoteCount": 7,
    "mediaType": "image",
    "media": [
        {
            "type": "image",
            "url": "https://example.com/media.jpg",
            "thumbnailUrl": null,
            "width": 1080,
            "height": 1350
        }
    ],
    "hashtags": ["launch"],
    "mentions": [],
    "date": "2025-01-15T12:00:00.000Z",
    "url": "https://www.threads.com/@exampleuser/post/ExampleCode1",
    "sourceUsername": "exampleuser",
    "searchQuery": null,
    "scrapedAt": "2025-01-15T12:05:00.000Z"
}
```

Download the dataset as JSON, CSV, Excel, XML, RSS, or HTML, or read it through the Dataset API.

### 💵 How much does it cost to scrape Threads?

The Actor uses pay-per-result pricing with no separate Actor-start charge:

- Post result: **$3.00 per 1,000** on the Free tier
- Profile result: **$5.00 per 1,000** on the Free tier

A run with 100 posts and one profile costs about **$0.305** in event charges on the Free tier. Higher Apify plans receive lower per-result prices. You pay only for rows you receive, so use `maxPosts` and the date filters to size a run - a `postedAfter` window stops paging early rather than fetching history you would discard.

### 🔁 Run it on the Apify platform

Schedule daily competitor checks, send datasets to Google Sheets, trigger Slack/webhook alerts, or call the Actor from Node.js, Python, cURL, and MCP. Every row includes its input source so multi-seed runs remain easy to split downstream.

### ⚠️ Limits and caveats

- **Posts mode paginates deep**, typically well past 100 posts per profile, but Threads still decides where a profile's public history ends. `maxPosts` is a ceiling, not a completeness guarantee.
- **Keyword search does not paginate.** Threads exposes a single page of public search results, roughly 20 posts per query, and raising `maxPosts` will not change that. Use posts mode when you need volume.
- Search results are ranked by Threads and may not be exhaustive or chronological.
- Media CDN URLs can expire. Persist permitted assets promptly if your workflow needs long-term copies.
- Deep profile runs make one request per page of results, so a 500-post seed takes noticeably longer than a 25-post one.
- `viewCount` is only populated when Threads attaches a public view count to a post, which is rare on logged-out pages.
- Meta can change its public web payloads without notice. Report a failed public URL in the Issues tab so the extractor can be updated.
- Only collect and use public data in accordance with applicable law, privacy rules, and Meta's terms.

### 🧩 Related Actors

- [Substack Scraper](https://apify.com/webdata_labs/substack-intelligence-scraper) - newsletter posts, comments and new-post monitoring.
- [TikTok Hashtag Trends Scraper](https://apify.com/webdata_labs/tiktok-hashtag-trends-scraper) - which hashtags are breaking out before they peak.
- [Meta Ads Library Scraper](https://apify.com/webdata_labs/meta-ads-library-scraper) - every Facebook and Instagram ad a competitor is running, with creatives.
- [LinkedIn Ads Library Scraper](https://apify.com/webdata_labs/linkedin-ads-library-scraper) - the B2B side of the same question: who is advertising what to whom.
- [TikTok Comments Scraper](https://apify.com/webdata_labs/tiktok-comments-scraper) - the comment thread under any video, with authors and engagement.

### ❓ FAQ

#### Does this Threads scraper require login?

No. It reads only data exposed on public Threads web pages without a Threads or Instagram account.

#### Can it scrape private accounts?

No. The Actor does not bypass privacy controls or login walls.

#### Why did I get fewer posts than `maxPosts`?

In posts mode, the account simply may not have that many public posts - the run log reports whether the profile was exhausted. Date filters reduce the set further. In search mode this is expected: Threads publishes only one page of public search results per query, about 20 posts, so `maxPosts` above that has no effect.

#### Is this an official Threads API?

No. It is an independent public-web scraper running on Apify. It is not affiliated with or endorsed by Meta.

#### Can I monitor accounts automatically?

Yes. Create an Apify Task with your input, schedule it daily or weekly, and deliver each dataset through an integration or webhook. Deduplicate downstream by `postId`.

### 🛠️ Support

Open the Actor's Issues tab and include the run URL, sanitized input, public Threads URL, expected behavior, and actual behavior. Do not include account credentials or private personal data.

# Actor input Schema

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

Choose profile metadata, public profile posts, or public keyword search results. Profile posts paginate deep; keyword search returns a single page of results.

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

Threads usernames or profile URLs for profile and posts modes. Up to 20 per run. Ignored in search mode.

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

Keywords to search across public Threads posts in search mode. Up to 20 per run. Ignored in profile and posts modes.

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

Maximum number of post rows returned for each username or search query. Posts mode pages until it reaches this number or the profile runs out. Keyword search is a single page and returns about 20 posts per query no matter what you set here.

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

Optional ISO 8601 date or timestamp. Includes posts published at or after this value. In posts mode the scraper stops paging once it passes this date, so a recent window costs less than a deep one.

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

Optional ISO 8601 date or timestamp. Excludes posts published at or after this value.

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

Include one profile metadata row for each username when using posts mode.

## Actor input object example

```json
{
  "mode": "posts",
  "usernames": [
    "zuck"
  ],
  "searchQueries": [
    "artificial intelligence"
  ],
  "maxPosts": 25,
  "includeProfile": true
}
```

# Actor output Schema

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

Dataset containing all extracted public Threads profiles and posts.

# 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": "posts",
    "usernames": [
        "zuck"
    ],
    "searchQueries": [
        "artificial intelligence"
    ],
    "maxPosts": 25,
    "includeProfile": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("webdata_labs/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 = {
    "mode": "posts",
    "usernames": ["zuck"],
    "searchQueries": ["artificial intelligence"],
    "maxPosts": 25,
    "includeProfile": True,
}

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

```

## MCP server setup

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